swift - 尝试执行 Realm 迁移时获取无效的属性名称

标签 swift realm realm-migration

我在使用 Realm 时遇到问题,它给我的错误是我的对象不存在给定名称的属性。但我知道它确实存在。

我尝试按照 https://realm.io/docs/swift/latest/#updating-values 上的文档进行操作.我已经搜索了所有我能想到的在这里和其他地方找到适用的解决方案,但我没有找到任何有效的方法。

我之前执行了一个简单的迁移,只是将属性添加到同一 Realm 内的不同对象。我只是将迁移 block 留空并且工作正常。该迁移应该将我的模式从 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"
    }

}

我的迁移 block :

    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 只是我编写的函数,用于从 Date 返回小时或分钟的 Int >。如果相关,它们就在这里。

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

最佳答案

我知道这不是执行此操作的方法,但我通过对迁移 block 采取稍微更手动的方法使其工作。我取消了 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()
}

这只有在我将它异步排队到另一个线程时才有效。我想如果这些数据对于我的初始 View Controller 是必需的,那么它可能会创建一个导致应用程序崩溃的竞争条件。幸运的是,这只出现在辅助 View 中,因此它有时间在需要这些值之前完成。我想我将不得不在我的应用程序的 future 版本中使用更新的 Realm 架构删除未使用的属性。

关于swift - 尝试执行 Realm 迁移时获取无效的属性名称,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53237005/

相关文章:

ios - iOS Realm 迁移内存泄漏

swift - 解决引发 SIGABRT 错误的核心数据关系

ios - UITableViewCell 3 选择的时间更改多个选择的背景颜色

java - 管理服务和应用程序之间的 Realm

ios - Realm :防止对对象进行不必要的更新

android - 从 Sqlite 迁移到 Realm (Android)

ios - 由于未捕获的异常无法安装约束而终止应用程序,原因 : No common superview between views

swift - NSArrayURL , userDefault 文件路径和 URL

ios - 快速将非 Realm 对象作为被忽略的属性添加到 Realm 对象?

ios - Realm 主键迁移 - Objective-C