I have an iOS/Swift app where I need to change and add some new properties to a Realm
object, which means I will have to create a new schema and change some of the existing data inside Realm
accordingly so it works with the new changes.
Where would be the best place to place my code to restructure the existing data inside Realm
as soon as the app launches?
EDIT:
I know how to create the migration and where to do it.
What I'm not sure is where would be a good place to iterate through all of the records in Realm
right after the migration code runs to make some changes to the existing data in Realm
.
To be more specific, the main reason I need to iterate though the records is because I'm currently using a String
property to store quantities
as follow... 2 pcs
, don't ask me why but now I need to remove pcs
from the quantity values to leave just the 2
to be able to change the property to an Int
or a Double
. I know I know, that was silly to use a string to store quantities.
Write migration code in AppDelegate's disFinishLaunchWithOptions
method.
Please refer below references:
Local migrations:
Local migrations are defined by setting Realm.Configuration.schemaVersion and Realm.Configuration.migrationBlock. Your migration block provides all the logic for converting data models from previous schemas to the new schema. When creating a Realm with this configuration, the migration block will be applied to update the Realm to the given schema version if a migration is needed.
Suppose we want to migrate the Person model declared earlier. The minimal necessary migration block would be the following:
// Inside your application(application:didFinishLaunchingWithOptions:)
let config = Realm.Configuration(
// Set the new schema version. This must be greater than the previously used
// version (if you've never set a schema version before, the version is 0).
schemaVersion: 1,
// Set the block which will be called automatically when opening a Realm with
// a schema version lower than the one set above
migrationBlock: { migration, oldSchemaVersion in
// We haven’t migrated anything yet, so oldSchemaVersion == 0
if (oldSchemaVersion < 1) {
// Nothing to do!
// Realm will automatically detect new properties and removed properties
// And will update the schema on disk automatically
}
})
// Tell Realm to use this new configuration object for the default Realm
Realm.Configuration.defaultConfiguration = config
// Now that we've told Realm how to handle the schema change, opening the file
// will automatically perform the migration
let realm = try! Realm()
Update:
realm.io official docs already all given information which is required for migration.
Local migrations
If you want to add new property only then above code will work for you. No need to iterate all records. The old record keeps its default value with the respective row.
Updating values
If you want to add a new property by using existing column value. You need to iterate all the records. Please refer below code.
// Inside your application(application:didFinishLaunchingWithOptions:)
Realm.Configuration.defaultConfiguration = Realm.Configuration(
schemaVersion: 1,
migrationBlock: { migration, oldSchemaVersion in
if (oldSchemaVersion < 1) {
// The enumerateObjects(ofType:_:) method iterates
// over every Person object stored in the Realm file
migration.enumerateObjects(ofType: Person.className()) { oldObject, newObject in
// combine name fields into a single field
let firstName = oldObject!["firstName"] as! String
let lastName = oldObject!["lastName"] as! String
newObject!["fullName"] = "\(firstName) \(lastName)"
}
}
})
Renaming properties
If you just want to rename property only then use below code.
// Inside your application(application:didFinishLaunchingWithOptions:)
Realm.Configuration.defaultConfiguration = Realm.Configuration(
schemaVersion: 1,
migrationBlock: { migration, oldSchemaVersion in
// We haven’t migrated anything yet, so oldSchemaVersion == 0
if (oldSchemaVersion < 1) {
// The renaming operation should be done outside of calls to `enumerateObjects(ofType: _:)`.
migration.renameProperty(onType: Person.className(), from: "yearsSinceBirth", to: "age")
}
})