多线程环境中的领域

时间:2017-05-04 06:32:27

标签: swift multithreading realm

我有一个跟踪应用程序在后台工作,使用Realm来保持持久性。我注意到有时收到的位置没有保存在Realm中的问题,我认为这可能因为多线程而发生。

这是我的架构:

LocationLogger有一个CLLocationManager实例和我的类的实例,用于持久性:LocationModel。 LocationManager的类型为BaseModel,此实例具有Realm的实例。在BaseModel中,realm从我的类RealmProvider加载一个Realm实例:

lazy var realm: Realm = {
    return RealmProvider().loadRealm()
}()!

RealmProvider的代码是这样的:

class RealmProvider {

    private var realm: Realm?
    private let currentSchemaVersion: UInt64 = 8

    func loadRealm() -> Realm? {

        if let realm = self.realm {
            return realm
        }

        do {
            if let _ = NSClassFromString("XCTest"){
                realm =  try Realm(configuration: Realm.Configuration(fileURL: nil, inMemoryIdentifier: "test", syncConfiguration: nil, encryptionKey: nil, readOnly: false, schemaVersion: currentSchemaVersion, migrationBlock: nil, deleteRealmIfMigrationNeeded: true, objectTypes: nil))
            } else {
                realm =  try Realm(configuration: Realm.Configuration(encryptionKey: nil, readOnly: false, schemaVersion: currentSchemaVersion, migrationBlock: nil, deleteRealmIfMigrationNeeded: true, objectTypes: nil))
            }
        }
        catch  {
            logger.error("eror loading Realm!")
        }
        return realm
    }
}

我有一个RealmProvider的原因是在一个地方进行类似版本控制的配置。

你能想象为什么它总是不起作用吗?也许当在线程A中创建LocationLogger时,位置回调会出现在线程B中?其他想法?

每次报告新位置时,创建Realm实例会更好吗?那我怎么做架构配置呢?

对最终解决方案的建议:

class RealmProvider {

    static private let currentSchemaVersion: UInt64 = 8

    private lazy var configuration: Realm.Configuration = {
        if let _ = NSClassFromString("XCTest") {
            return Realm.Configuration(inMemoryIdentifier: "test", schemaVersion: currentSchemaVersion, deleteRealmIfMigrationNeeded: true)
        }
        return Realm.Configuration(schemaVersion: currentSchemaVersion, deleteRealmIfMigrationNeeded: true)
    }()

    public var realm: Realm {

        var tempRealm: Realm?
        do {
            tempRealm = try Realm(configuration: configuration)
        }
        catch  {
            logger.error("eror loading Realm!")
        }

        if let tempRealm = tempRealm{
            return tempRealm
        }

        return self.realm
    }
}

1 个答案:

答案 0 :(得分:0)

是。最好是按需创建Realm实例,而不是提前创建实例并保留它。由于Realm对象是线程限制的,因此在线程A上创建Realm,然后尝试在线程B上与它进行交互将导致异常。

当调用Realm(configuration:)时,Realm本身将在内部缓存该对象,并在每次后续调用时返回相同的对象。该对象保留在缓存中,直到创建它的自动释放池耗尽。

就像我上面所说,Realm对象是线程限制的。在新线程上运行时,必须创建Realm的新实例。尝试从另一个线程传递Realm的实例将触发异常。这是为什么建议不要保留Realm的实例的主要原因,特别是如果存在后台操作。

领域Configuration对象,只要它们在创建 线程安全后未被修改。因此,创建和保留Configuration实例,然后重新使用此实例在任何后续线程上创建Realm实例是完全合理的。

所以要修改上面的例子:

class RealmProvider {
    private let currentSchemaVersion: UInt64 = 8

    private lazy var configuration: Configuration = {
        if let _ = NSClassFromString("XCTest") {
            return Realm.Configuration(inMemoryIdentifier: "test", schemaVersion: currentSchemaVersion,deleteRealmIfMigrationNeeded: true)
        }

        return Realm.Configuration(schemaVersion: currentSchemaVersion, deleteRealmIfMigrationNeeded: true)
    }()

    public var realm: Realm? {
        var realm: Realm?
        do {
            realm = try Realm(configuration: configuration)
        }
        catch  {
            logger.error("eror loading Realm!")
        }
        return realm
    }
}