在后台线程中执行 Realm 本地迁移是否安全?

Is it safe to perform Realm local migration in background thread?

我们正在优化应用程序启动时间,其中一个巨大的减速来自领域初始化。

我们有这段代码,在 didFinishLaunchingWithOptions

期间调用过
RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init];
config.schemaVersion = kCurrentSchema;
config.migrationBlock = /* migration task */;
config.fileURL = fileUrl;
config.encryptionKey = encryptionKey;
    
return config;

在初始化期间,我们尝试使用此配置至少创建一次 RLMRealm 以查看我们是否能够打开领域。如果打开失败,那么我们使用 NSFileManager 执行删除 Realm 文件夹的操作并重新开始。 一切都完成后我们设置

[RLMRealmConfiguration setDefaultConfiguration:config];

我的问题是

  1. 我们可以把创建RLMRealmConfiguration和初始化RLMRealm的整个过程移到后台线程吗?
  2. 迁移完成后,我们能否将在后台线程中创建的 RLMRealmConfiguration 分派到主线程以在主线程上调用 setDefaultConfiguration
  3. 在主线程上成功迁移并分派调用[RLMRealmConfiguration setDefaultConfiguration:config];后,后台线程的迁移结果是写入文件还是仍在内存中?如果我在 setDefaultConfiguration 之后直接在主线程上创建另一个 RLMRealm。我可以访问迁移后的版本吗?我知道 RLMThreadSafeReference 但只有在我们知道如何访问时才能使用。就我而言,设置后我们将有太多访问权限。

创建新的 RLMRealmConfiguration 和调用 setDefaultConfiguration 是微不足道的操作。它们都不会触发迁移。

在您打开领域之前不会运行迁移。

有几种方法可以在后台线程中迁移到 运行。我将在 Swift 中向您展示最简单的方法。您必须将此代码翻译成 Objective-C:

enum Migrator {

    static func migrate(completion: @escaping () -> Void) {

        let queue = DispatchQueue(label: "migrator.awesome")

        let configuration = Realm.Configuration(
            schemaVersion: 13,
            migrationBlock: { migration, oldSchemaVersion in
                if oldSchemaVersion < 1 {
                    // ...
                }
                if oldSchemaVersion < 2 {
                    // ...
                }
                if oldSchemaVersion < 3 {
                    // ...
                }
                // ...
            }
        )

        Realm.asyncOpen(configuration: configuration, callbackQueue: queue) { result in

            Realm.Configuration.defaultConfiguration = configuration

            switch result {
            case .failure(let error):
                print("error", error)
            case .success(let realm):
                print("realm", realm)
                break
            }
            completion()
        }
    }
}

asyncOpen 将打开一个领域并 运行 指定队列上的迁移。在您的情况下,您想传入一个后台队列。一旦迁移 运行s asyncOpen 将在您指定的同一队列上调用指定的回调。

迁移完成后,您可以切换回主线程并执行您需要执行的任何操作。是的,在后台线程中迁移的数据将可用于主线程。

enum RealmInitializer {
    static func initializeRealm() {
        Migrator.migrate {
            DispatchQueue.main.async {
                readAndWriteRealmData()
            }
        }
    }
}