Получение неверного имени свойства при попытке выполнить миграцию Realm - PullRequest
0 голосов
/ 10 ноября 2018

У меня проблемы с тем, что Realm выдает ошибку, что для моего объекта не существует свойства с заданным именем. Но я знаю, что оно существует.

Я пытался следовать документам на https://realm.io/docs/swift/latest/#updating-values. Я искал все, что мог придумать, чтобы найти подходящее решение здесь и в других местах, но ничего не нашел работ.

Ранее я выполнял простую миграцию, чтобы просто добавить свойства к другому объекту в той же области. Я просто оставил блок миграции пустым, и это работало нормально. Эта миграция должна была установить мою схему от 0 до 1. Если я запускаю ее с моей схемой, установленной в 1, и проверяю версии менее 2, это говорит мне, что миграция должна быть запущена для добавления этих свойств. Миграция запущена. У меня есть заявление для печати каждый раз, когда оно выполняется. Если я установлю схему на 2, продолжая проверять менее 2, я получу ошибку для недопустимого имени свойства для старых свойств, если я не раскомментирую их. Тогда я все еще получаю ошибку для новых свойств.

Вот мой объект Царства. Закомментированные строки - это старые свойства, из которых я хочу перейти. Значения 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)
                })
            }
    })

getHour и getMinute - это просто функции, которые я написал для возврата 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 голосов
/ 11 ноября 2018

Я знаю, что это не способ сделать это, но я заставил это работать, применив немного более ручной подход к блоку миграции. Я раскомментировал старые свойства в объекте 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 в будущей версии моего приложения.

...