使用ThreadSafeReference只能获得动态值

时间:2017-09-06 05:18:07

标签: ios multithreading realm

我有一个StoreArea表,在调用api后获取Store Area数据,然后会创建StoreArea表;

目标:对于渲染ui,我需要Store areaName。从db获取存储,然后使用areaName组合到存储,然后在后台线程中根据areaName组成一个二维数组。然后传递2d数组以在主线程中呈现ui

实施:

在后台线程中读取Store,使用areaCode获取Area,然后获取areaName,然后store.areaName = area.areaName获取组合Store,并使用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

请列出通过线程传递realm对象的方法吗? 我目前知道以下方法: 1. ThreadSafeReference(在我的情况下失败) 2.自己将领域对象转换为普通类

1 个答案:

答案 0 :(得分:0)

对于这个简单的情况,您实际上并不需要使用ThreadSafeReference对象。您应该只将对象的属性保存到可用于标识该特定对象的变量(如果您使用primaryKey s,则优选为primaryKey),然后使用Realm中的主键检索对象在主线上。

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)

由于您在主线程上声明了对Realm实例的新引用并从该引用访问Store对象,因此您不会收到任何错误。

根据评论更新:

您的Class模型存在缺陷。您希望在Realm中保留的所有属性都需要使用dynamic关键字声明,否则无法将它们动态分派到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
}

其次,如果要修改实际的Store对象,为什么要将ThreadSafeReference存储到各个商店,您可以在写入事务中执行此操作并将ThreadSafeReference存储到Results 1}}实例,因此您只需要解析单个引用,而不是每个单独的Store。

以下代码已经过测试,正在Realm游乐场工作。

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)
}