We in the process of optimizing app startup time and one of the huge slow down come from realm initialization.
We have this code which has been called during didFinishLaunchingWithOptions
RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init];
config.schemaVersion = kCurrentSchema;
config.migrationBlock = /* migration task */;
config.fileURL = fileUrl;
config.encryptionKey = encryptionKey;
return config;
During the initialization we try to create RLMRealm
at least once using this configuration to see that we able to open realm or not. If the opening fail then we perform operations to remove Realm folder using NSFileManager
and start anew.
After everything is done we set
[RLMRealmConfiguration setDefaultConfiguration:config];
My question is
- Can we move the whole process of creating
RLMRealmConfiguration
and initializeRLMRealm
in background thread? - Can we dispatch
RLMRealmConfiguration
create in background thread to main thread to callsetDefaultConfiguration
on main thread after the migration is done?. - After successful migration and dispatch to call
[RLMRealmConfiguration setDefaultConfiguration:config];
on main thread, the migration result from background thread is written to the file or still in memory? If I create anotherRLMRealm
on main thread directly aftersetDefaultConfiguration
. Can I access the migrated version? I know aboutRLMThreadSafeReference
but that only to be used when we know how to access. In my case, we will have too many accesses after the setup.
CodePudding user response:
Creating a new RLMRealmConfiguration and calling setDefaultConfiguration are trivial operations. Neither of them trigger migrations.
Migrations don't run until you open a realm.
There are a couple of ways to cause the migration to run in a background thread. I'll show you the easiest way in Swift. You'll have to translate this code to 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
will open a realm and run the migration on the specified queue. In your case, you want to pass in a background queue. Once the migration runs asyncOpen
will invoke the specified callback on the same queue you specified.
Once the migration is complete you can switch back to the main thread and do whatever you need to do. And yes, the data that was migrated in the background thread will be available to the main thread.
enum RealmInitializer {
static func initializeRealm() {
Migrator.migrate {
DispatchQueue.main.async {
readAndWriteRealmData()
}
}
}
}