Ios 使用ThreadSafeReference只能获取动态值

Ios 使用ThreadSafeReference只能获取动态值,ios,multithreading,realm,Ios,Multithreading,Realm,我有一个存储,区域表,调用api后得到存储区域数据,然后将创建存储,区域表 目标:对于渲染ui,我需要使用areaName存储。从数据库获取存储,然后使用areaName组合到存储,然后基于后台线程中的areaName组合到二维数组。然后将2d数组传递给主线程中的渲染ui 实施: 在后台线程读取Store,使用areaCode获取Area,然后获取areaName,然后使用Store.areaName=Area.areaName获取组合存储,并使用ThreadSafeReference获取存储的

我有一个
存储
区域
表,调用api后得到
存储
区域数据,然后将创建
存储
区域

目标:对于渲染ui,我需要使用
areaName
存储
。从数据库获取存储,然后使用
areaName
组合到存储,然后基于后台线程中的
areaName
组合到二维数组。然后将2d数组传递给主线程中的渲染ui

实施:

在后台线程读取Store,使用areaCode获取Area,然后获取areaName,然后使用
Store.areaName=Area.areaName
获取组合存储,并使用
ThreadSafeReference
获取存储的引用

在主线程中使用
realm.resolve
获取主线程中的存储,但只能获取
store.address
值,无法获取
store.areaName

class Store: Object {
    dynamic var storeCode: String = ""

    dynamic var areaCode: String = ""

    dynamic var address: String = ""
    dynamic var phone: String = ""

    var areaName: String = ""
    var userId: Int = 0
}


class Area: Object {
    dynamic var areaCode: String = ""
    dynamic var areaName: String = ""
}

//// in background thread//////
let realmInBack = try! Realm()
let stores = getStore(by userId: Int) // here get a list of stores from db
stores.forEach{ (store) in
    let area = getArea(by areaCode: String) // get area
    let areaName = area.areaName // get the areaName from area
    store.areaName = areaName // assign areaName to store
    let storeRef = ThreadSafeReference(to: store) // get the storeRef
}
//// in main thread /////
let realm = try! Realm()
let storeInMain = realm.resolve(storeRef)
// then use storeInMain to render ui
请列出通过线程传递领域对象的方式好吗? 我目前知道以下方法: 1.ThreadSafeReference(在我的案例中失败)
2.自己将realm对象转换为普通类

对于这种简单的情况,实际上不需要使用
ThreadSafeReference
对象。您只需将对象的属性保存到一个变量中,该变量可用于标识该特定对象(如果您使用的是
primaryKey
s,最好是它的
primaryKey
s),然后使用它的主键从主线程的领域中检索该对象

var storeCodeRef = "" //make sure this variable is accessible in the scope of where your code on the main thread is called from as well

let realmInBack = try! Realm()
let stores = getStore(by userId: Int) // here get a list of stores from db
stores.forEach{ (store) in
    let area = getArea(by areaCode: String) // get area
    let areaName = area.areaName // get the areaName from area
    store.areaName = areaName // assign areaName to store
    //save the unique identifier for the store
    storeCodeRef = store.storeCode
}

//// in main thread /////
let realm = try! Realm()
let store = realm.object(ofType: Store.self).filter("storeCode == %@",storeCodeRef).first //assuming storeCodes are unique
如果您使用的是主键,则可以使用

let store = realm.object(ofType: Store.self, forPrimaryKey: storeCodeRef)
由于您在主线程上声明了对领域实例的新引用,并从该引用访问
存储
对象,因此不会收到任何错误

根据评论更新:

您的
模型有缺陷。需要使用
dynamic
关键字声明要在Realm中持久化的所有属性,否则无法将它们动态调度到Realm使用的Obj-C运行时

class Store: Object {
    dynamic var storeCode: String = ""
    dynamic var areaCode: String = ""
    dynamic var address: String = ""
    dynamic var phone: String = ""
    dynamic var areaName: String = ""
    dynamic var userId: Int = 0
}
其次,为什么要将
ThreadSafeReference
s存储到各个存储区如果要修改实际的存储区对象,可以在写入事务中这样做,并将
ThreadSafeReference
存储到
Results
实例,因此只需解析单个引用,而不必解析每个存储区的引用

下面的代码已经过测试,正在一个领域中工作

class Store: Object {
    dynamic var storeCode: String = ""
    dynamic var address: String = ""
    dynamic var phone: String = ""
    dynamic var userId: Int = 0
    dynamic var areaCode: String = ""
    dynamic var areaName: String = ""
}


class Area: Object {
    dynamic var areaCode: String = ""
    dynamic var areaName: String = ""
}

try! realm.write {
    realm.add([Store(value: ["userId":1,"storeCode":"1"]),Store(value: ["userId":1,"storeCode":"2"]),Store(value: ["userId":2,"storeCode":"1"])])
}

print(realm.objects(Store.self))

//// in some thread//////
var storesRef: ThreadSafeReference<Results<Store>>?
DispatchQueue(label: "background").sync {
    autoreleasepool{
        let realmInBack = try! Realm(configuration: Realm.Configuration(inMemoryIdentifier: "TemporaryRealm"))
        let stores = realmInBack.objects(Store.self).filter("userId == 1")
        print("Stores for user 1:",stores)
        try! realmInBack.write {
            let area = Area(value: ["areaCode":"a","areaName":"AreaA"])
            realmInBack.add(area)
            stores.forEach{ (store) in
                store.areaCode = area.areaCode
            }
        }
        print("Modified stores:",stores)
        storesRef = ThreadSafeReference(to: stores)
    }
}
//// in main thread /////
DispatchQueue.main.async {
    let mainRealm = try! Realm(configuration: Realm.Configuration(inMemoryIdentifier: "TemporaryRealm"))
    guard let storesRef = storesRef, let storeInMain = mainRealm.resolve(storesRef) else {
        print("Couldn't resolve stores reference"); return
    }
    print("Stores from ThreadSafeReference:",storeInMain)
}
类存储:对象{
动态变量storeCode:String=“”
动态变量地址:String=“”
动态变量phone:String=“”
动态变量userId:Int=0
动态变量区域代码:String=“”
动态变量areaName:String=“”
}
类区域:对象{
动态变量区域代码:String=“”
动态变量areaName:String=“”
}
尝试realm.write{
realm.add([Store(value:[“userId:1”,storeCode“:”1“]”),存储(值:[“userId”:1,“storeCode”:“2”]),存储(值:[“userId”:2,“storeCode”:“1”])
}
打印(realm.objects(Store.self))
////以某种方式//////
var storesRef:ThreadSafeReference?
DispatchQueue(标签:“后台”).sync{
自动释放池{
让realmInBack=try!Realm(配置:Realm.configuration(inMemoryIdentifier:“TemporaryRealm”))
让stores=realmInBack.objects(Store.self.filter)(“userId==1”)
打印(“用户1的存储:”,存储)
试试!realmInBack.write{
让面积=面积(值:[“areaCode”:“a”,“areaName”:“AreaA”])
realmInBack.add(区域)
stores.forEach{(store)in
store.areaCode=area.areaCode
}
}
打印(“修改的存储:”,存储)
storesRef=ThreadSafeReference(收件人:stores)
}
}
////主线程中/////
DispatchQueue.main.async{
让mainRealm=try!Realm(配置:Realm.configuration(inMemoryIdentifier:“TemporaryRealm”))
guard let storesRef=storesRef,let storeInMain=mainRealm.resolve(storesRef)else{
打印(“无法解析存储引用”);返回
}
打印(“存储自ThreadSafeReference:,storeInMain)
}

请显示实际用于从不同线程访问对象的代码。在目前的形式下,你的问题相当笼统,很难给你一个具体的答案。此外,请遵守Swift命名约定,即变量名称的小写形式(例如
storeCode
,而不是
store\u code
)。感谢您的评论,我已经重新编辑了这个问题。在我的例子中,我在后台线程中得到一个realmObject,然后需要将realmObject传递给主线程以呈现ui。我怎么能做到?你能帮我列出制作的方法吗?非常感谢你的回答。在实际案例中,我仍然存在以下问题:1。存储表没有唯一键(由“storeCode”、“channelCode”、“startDate”、“endDate”查询)2。在后台线程中,我想用额外的数据组合存储,然后基于areaName组合成2d数组。然后将2d数组传递给主线程。在您的回答中,我必须再次重新蚀刻存储,然后在主线程中合成为2d数组@苏文梁 检查我的更新答案,包括使用“ThreadSafeReference”的工作代码。感谢您的工作,这真的很有帮助。我还有一个问题要确认:如果使用ThreadSafeReference通过线程传递对象,只能传递动态属性,不能传递忽略的属性?如果是这样,我将把areaName声明为动态属性。在这里,我将areaName声明为忽略属性,因为当调用api get时,存储信息没有areaName keyYes,因为您正在从
领域
检索持久化值,所以忽略的属性将被删除。顺便说一句,声明被忽略的属性时不应使用
dynamic
关键字。您需要将它们添加到
ignoredProperties
函数中,以使它们成为正确的忽略属性。感谢您的帮助。现在我还有