Search code examples
iosswiftrealm

Iterate through all of the records in Realm right after a migration runs - Swift / iOS


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.


Solution

  • Write migration code in AppDelegate's disFinishLaunchWithOptions method.

    Please refer below references:

    realm.io official docs

    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")
                }
            })