在后台线程中执行 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];
我的问题是
- 我们可以把创建
RLMRealmConfiguration
和初始化RLMRealm
的整个过程移到后台线程吗?
- 迁移完成后,我们能否将在后台线程中创建的
RLMRealmConfiguration
分派到主线程以在主线程上调用 setDefaultConfiguration
?
- 在主线程上成功迁移并分派调用
[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()
}
}
}
}
我们正在优化应用程序启动时间,其中一个巨大的减速来自领域初始化。
我们有这段代码,在 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];
我的问题是
- 我们可以把创建
RLMRealmConfiguration
和初始化RLMRealm
的整个过程移到后台线程吗? - 迁移完成后,我们能否将在后台线程中创建的
RLMRealmConfiguration
分派到主线程以在主线程上调用setDefaultConfiguration
? - 在主线程上成功迁移并分派调用
[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()
}
}
}
}