swift - 多线程环境中的 Realm

标签 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 的原因是为了将模式版本控制之类的配置集中在一个地方。

你能想象为什么这并不总是有效吗?也许当 LocationLogger 在线程 A 中创建并且位置回调出现在线程 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
    }
}

最佳答案

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

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

就像我上面所说的,Realm 对象是线程限制的。在新线程上运行时,有必要创建一个新的Realm实例。尝试从另一个线程传递Realm实例将触发异常。这是建议不要保留 Realm 实例的主要原因,尤其是在存在后台操作的情况下。

Realm 配置对象,只要它们在创建后不被修改都是线程安全的。因此,创建并保留一个 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
    }
}

关于swift - 多线程环境中的 Realm,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43775459/

相关文章:

swift - 测试在 vapor 应用程序中不起作用

swift - 尝试添加其他文本字段时,为什么我的标签不会更改位置?

c# - 使用信号量保护队列的问题

java - 如何使用一个 WatchService 注册多个文件夹

c# - 如何在 C# 中实现我自己的 TaS-Lock?

android - 辅助 .realm 文件 getInstance 花费的时间太长

json - 用 alamofire 改变编码体

ios - 在水平堆栈 View 中居中对齐交换机

java - 在 RealmRecyclerViewAdapter 上调用 updateData 实际上并不是更新数据

ios - Realm 安装XCode 8.1