Reputation: 484
I recently upgrade my Realm library from 0.92 (I think) to 0.96.2, but am having some trouble with the new support for ‘optional’ properties. I also need to do a migration for the first time, which is also complicating matters.
The new scheme needed to add a single field to one of the data types, so I coded up a migration that establishes this new property on existing objects:
RLMRealmConfiguration* config = [RLMRealmConfiguration defaultConfiguration];
config.schemaVersion = 1;
config.migrationBlock = ^(RLMMigration* migration, uint64_t oldSchemaVersion)
{
[migration enumerateObjects:Foo.className
block:^(RLMObject* oldObject, RLMObject* newObject) {
if (oldSchemaVersion < 1)
{
newObject[@"user"] = @"";
}
}];
};
[RLMRealmConfiguration setDefaultConfiguration:config];
However, as soon as the code tries to open a Realm, I get an error message about optional property types:
'Migration is required for object type 'Person' due to the following errors:
- Property 'name' has been made optional.
- Property ‘company’ has been made optional.
- Property 'title' has been made optional.
- Property 'phone' has been made optional.
- Property 'email' has been made optional.
- Property 'homeAddress' has been made optional.'
Question #1 - Since the model is going from ‘required’ properties to ‘optional’, there’s guaranteed to be a value already present for existing objects; so I’m struggling to see why a migration is required.
Question #2 - I’d still like to migrate the objects, and nil out the properties if the string is empty, so I coded up a migration:
RLMRealmConfiguration* config = [RLMRealmConfiguration defaultConfiguration];
config.schemaVersion = 1;
config.migrationBlock = ^(RLMMigration* migration, uint64_t oldSchemaVersion)
{
NSLog(@"RUNNING REALM MIGRATION");
// ...basic migration of adding a new property (above)
[migration enumerateObjects:Person.className
block:^(RLMObject* oldObject, RLMObject* newObject) {
if (oldSchemaVersion < 1)
{
if ([oldObject[@"name"] length] == 0)
newObject[@"name"] = nil;
else
newObject[@"name"] = oldObject[@"name"];
// … repeat for other properties
}
}];
};
[RLMRealmConfiguration setDefaultConfiguration:config];
However, the migration doesn’t appear to be run; a breakpoint inside the if (oldSchemaVersion < 1)
block is never hit, and the "RUNNING REALM MIGRATION"
message never prints.
The outer block — setting up the RLMRealmConfiguration
— is hit inside application:didFinishLaunchingWithOptions:
Upvotes: 0
Views: 2004
Reputation: 484
The issue seems to be that I'm setting up the default RLMRealmConfiguration
with my migration info, but [RLMRealm realmWithPath:]
ignores the default configuration.
Instead of using realmWithPath:
, you can copy the default configuration (including your migrationBlock
and schemaVersion
), set the path
property, and pass it to [RLMRealm realmWithConfiguration:error:]
RLMRealmConfiguration* config = [RLMRealmConfiguration defaultConfiguration];
config.path = file;
NSError* error = nil;
RLMRealm* realm = [RLMRealm realmWithConfiguration:config
error:&error];
Upvotes: 0
Reputation: 15991
Question #1 By default, all properties were designated 'required' in Realm versions before 0.96. In 0.96, they are marked as 'optional' by default. As such, due to the changes in the new underlying file format to accomodate this (relatively non-trivial change), a migration is required to convert these previously required properties to optional.
If you want to keep these properties as required, you can define this by overriding the [RLMObject requiredProperties]
method.
Question 2
Hmm... looking at the sample code, it recommends you encapsulate the enumeration statement inside the if (oldSchemaVersion < 1)
conditional block, not the other way around. It's possible that might be causing things to happen out of order. Have you tried swapping that around?
Let me know if that helps! :)
Upvotes: 1