Swift中的Realm迁移

21

我有一个Realm对象,其模型如下:

class WorkoutSet: Object {
     // Schema 0
     dynamic var exerciseName: String = ""
     dynamic var reps: Int = 0
     // Schema 0 + 1
     dynamic var setCount: Int = 0
}

我正在尝试进行迁移。

在我的AppDelegate中,我已经导入了RealmSwift

didFinishLaunchWithOptions函数中,我调用:

Migrations().checkSchema()

迁移是在另一个文件中声明的一个类。

在该文件中,有一个如下所示的结构体声明。

func checkSchema() {
    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
            switch oldSchemaVersion {
            case 1:
                break
            default:
                // Nothing to do!
                // Realm will automatically detect new properties and removed properties
                // And will update the schema on disk automatically
                self.zeroToOne(migration)
            }
    })
}

func zeroToOne(migration: Migration) {
    migration.enumerate(WorkoutSet.className()) {
        oldObject, newObject in
        let setCount = 1
        newObject!["setCount"] = setCount
    }
}

我在向模型添加setCount时遇到了错误。


你收到了哪些错误提示?可以分享一下吗? - Shripada
最新的模型中已添加了属性“setCount”。 - Cody Weaver
3个回答

38

您需要调用迁移。仅创建配置不会调用它。有两种方法可以做到这一点:

  1. 将带有迁移的配置设置为Realm的默认配置-

  2. 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
    
        if oldSchemaVersion < 1 {
          migration.enumerate(WorkoutSet.className()) { oldObject, newObject in
            newObject?["setCount"] = setCount
          }    
        }
      }
    ) 
    Realm.Configuration.defaultConfiguration = config   
    

或者

  1. 使用 migrateRealm 手动迁移:

migrateRealm(config)

现在您的迁移应该正常工作。


有没有一种自动完成这个操作的方法?如果该值为nil,我认为这很简单...你有什么想法吗? - Lucas Chwe

6
因为你只是创建了 Realm.Configuration。如果需要,迁移块将由 Realm 调用。你不能直接调用迁移。
因此,要调用迁移块,你应该将配置对象设置为 Realm,或将其设置为默认配置。然后创建 Realm 实例。
所以你需要执行以下操作:
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
        switch oldSchemaVersion {
        case 1:
            break
        default:
            // Nothing to do!
            // Realm will automatically detect new properties and removed properties
            // And will update the schema on disk automatically
            self.zeroToOne(migration)
        }
})

let realm = try! Realm(configuration: config) // Invoke migration block if needed

不要忘记调用 import RealmSwift。 - Ronaldo Albertini
7
不要在调用 let realm = try! Realm(configuration: config) 时使用 force。它被标记为可抛出的有其原因(例如设备上没有足够空间执行迁移)。相反,你应该在 do-catch 块中调用它。 - Gienadij Mackiewicz

0

更新针对Xcode 14.3的答案@kishikawa katsumi:

func zeroToOne(migration: Migration) {
    migration.enumerateObjects(ofType: <Your Realm Object>.className()) { _, newObject in
        newObject![<Your new properties>] = nil
        // Ex: newObject!["release_date"] = nil
    }
}

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
        switch oldSchemaVersion {
        case 1:
            break
        default:
            // Nothing to do!
            // Realm will automatically detect new properties and removed properties
            // And will update the schema on disk automatically
            zeroToOne(migration: migration)
        }
    }
)

let realm = try! Realm(configuration: config) // Invoke migration block if needed

这并没有更新参考答案。您复制了该答案的代码而没有做出任何更改。看起来您只是更改了原始问题的 zeroToOne 函数。 - HangarRash
是的。它从“enumerate”更改为“enumerateObjects(ofType:)”。 - kien-hoang

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接