尝试执行领域迁移时获取无效的属性名称

时间:2018-11-10 07:45:34

标签: swift realm realm-migration

我在使用Realm时遇到麻烦,给我这样的错误:我的对象不存在具有给定名称的属性。但我知道它确实存在。

我尝试关注https://realm.io/docs/swift/latest/#updating-values上的文档。我已经搜索了所有可以想到的东西,以在此处和其他地方找到适用的解决方案,但没有找到任何可行的方法。

我以前执行过一个简单的迁移,只是将属性添加到同一Realm中的另一个对象。我只是将迁移块留空,并且工作正常。该迁移应该将我的架构从0设置为1。如果我在将我的架构设置为1的情况下运行它并检查版本是否小于2,它告诉我必须运行迁移才能添加这些属性。迁移正在运行。每当执行时,我都有一个打印语句。如果将模式设置为2,但仍检查是否小于2,除非取消注释旧属性,否则会收到错误的旧属性名称错误。然后我仍然会收到新属性的错误。

这是我的Realm对象。注释掉的行是我要从中迁移的旧属性。我要迁移到Int值。

@objcMembers class Options: Object {

//    dynamic var morningStartTime: Date?
//    dynamic var afternoonStartTime: Date?
//    dynamic var eveningStartTime: Date?
//    dynamic var nightStartTime: Date?

    dynamic var morningHour: Int = 7
    dynamic var morningMinute: Int = 0

    dynamic var afternoonHour: Int = 12
    dynamic var afternoonMinute: Int = 0

    dynamic var eveningHour: Int = 17
    dynamic var eveningMinute: Int = 0

    dynamic var nightHour: Int = 21
    dynamic var nightMinute: Int = 0

    dynamic var morningNotificationsOn: Bool = true
    dynamic var afternoonNotificationsOn: Bool = true
    dynamic var eveningNotificationsOn: Bool = true
    dynamic var nightNotificationsOn: Bool = true

    dynamic var firstItemAdded: Bool = false

    dynamic var smartSnooze: Bool = false

    dynamic var optionsKey = UUID().uuidString
    override static func primaryKey() -> String? {
        return "optionsKey"
    }

}

我的迁移阻止:

    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: 2,

        // 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 < 2) {

                migration.enumerateObjects(ofType: Options.className(), { (newObject, oldObject) in
                    let morningStartTime = oldObject!["morningStartTime"] as! Date?
                    let afternoonStartTime = oldObject!["afternoonStartTime"] as! Date?
                    let eveningStartTime = oldObject!["eveningStartTime"] as! Date?
                    let nightStartTime = oldObject!["nightStartTime"] as! Date?

                    newObject!["morningHour"] = self.getHour(date: morningStartTime)
                    newObject!["morningMinute"] = self.getMinute(date: morningStartTime)

                    newObject!["afternoonHour"] = self.getHour(date: afternoonStartTime)
                    newObject!["afternoonMinute"] = self.getMinute(date: afternoonStartTime)

                    newObject!["eveningHour"] = self.getHour(date: eveningStartTime)
                    newObject!["eveningMinute"] = self.getMinute(date: eveningStartTime)

                    newObject!["nightHour"] = self.getHour(date: nightStartTime)
                    newObject!["nightMinute"] = self.getMinute(date: nightStartTime)
                })
            }
    })

getHourgetMinute只是我编写的从Int返回一个小时或分钟的Date的函数。如果相关,请在这里。

func getHour(date: Date?) -> Int {
    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "HH"
    let hour = dateFormatter.string(from: date!)
    return Int(hour)!
}

func getMinute(date: Date?) -> Int {
    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "mm"
    let minutes = dateFormatter.string(from: date!)
    return Int(minutes)!
}

1 个答案:

答案 0 :(得分:0)

我知道这不是做到这一点的方法,但是我通过对迁移块采用稍微更手动的方法来使其工作。我取消了Options对象中的旧属性的注释,并将迁移函数更改为以下内容:

func migrateRealm() {

    let configCheck = Realm.Configuration();
    do {
        let fileUrlIs = try schemaVersionAtURL(configCheck.fileURL!)
        print("schema version \(fileUrlIs)")
    } catch  {
        print(error)
    }

    print("performing realm migration")
    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: 2,

        // 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
            print("oldSchemaVersion: \(oldSchemaVersion)")
            if (oldSchemaVersion < 2) {
                print("Migration block running")
                DispatchQueue(label: self.realmDispatchQueueLabel).async {
                    autoreleasepool {
                        let realm = try! Realm()
                        let options = realm.object(ofType: Options.self, forPrimaryKey: self.optionsKey)

                        do {
                            try realm.write {
                                if let morningTime = options?.morningStartTime {
                                    options?.morningHour = self.getHour(date: morningTime)
                                    options?.morningMinute = self.getMinute(date: morningTime)
                                }
                                if let afternoonTime = options?.afternoonStartTime {
                                    options?.afternoonHour = self.getHour(date: afternoonTime)
                                    options?.afternoonMinute = self.getMinute(date: afternoonTime)
                                }
                                if let eveningTime = options?.eveningStartTime {
                                    options?.eveningHour = self.getHour(date: eveningTime)
                                    options?.eveningMinute = self.getMinute(date: eveningTime)
                                }
                                if let nightTime = options?.nightStartTime {
                                    options?.nightHour = self.getHour(date: nightTime)
                                    options?.nightMinute = self.getMinute(date: nightTime)
                                }
                            }
                        } catch {
                            print("Error with migration")
                        }

                    }
                }
            }
    })

    // 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
    _ = try! Realm()
}

这仅在我将它异步地在另一个线程上排队时才有效。我想如果这些数据对于我的初始视图控制器来说是必需的,那么它很可能创建了导致应用崩溃的竞争状态。幸运的是,这仅出现在辅助视图中,因此在需要这些值之前有时间来完成。我想我将来的应用程序版本中必须使用更新的Realm架构删除未使用的属性。