лучший способ переименовать класс в Realm swift

Я использую «обычную» библиотеку в своем проекте iOS. Эта библиотека создает базу данных Realm. Пока что я использую эту библиотеку только в проектах iOS. Теперь я хочу использовать ту же библиотеку с проектом macOS. Он основан на Foundation и не использует UIKit, так почему бы и нет?

Вот проблема: у меня есть класс Realm с именем Collection

Collection - это также название стандартного протокола Swift.

Хотя мне удалось избежать столкновения имен в моем проекте iOS, по какой-то причине я не могу сделать то же самое в моем проекте MacOS - он создает коллекцию имен.

Я читал об этой нотации, которую можно использовать так:

@objc(SpecialCollection)
class Collection: Realm.Object {
   let items: List<ItemObject>
   let name: String
   let url: String
  ....
}

Итак, это решает проблему конфликта имен. В ObjC имя будет другим, но в Swift мне ничего менять не нужно.

Это все хорошо, за исключением моей локальной базы данных Realm. У меня много Collection объектов, которые следует переименовать в SpecialCollection (поскольку Realm использует ObjC под Swift). Я хотел бы выполнить миграцию для этого, но, по-видимому, еще нет поддерживаемого способа сделать это? Я заметил на github тикеты о том, что за этой проблемой «наблюдают», но, к сожалению, до сих пор не существует опубликованного решения для решения этой проблемы.

Все мои Collection объекты содержат List объектов (отсюда и название). Итак, я попытался выполнить перечисление всех Collection объектов в миграции ... Я бы просто взял старый объект и создал новый объект с новым именем, например:

 migration.enumerateObjects(ofType: "Collection", { (oldObject, _) in
    migration.create("SpecialCollection", value: oldObject)
 }

Но поскольку у oldObject есть список других объектов, миграция Realm попытается создать все элементы в любых List объектах ... что невозможно, потому что он создает объекты с тем же значением primaryKey (вызывая сбой).

Итак, я не могу сохранить старое имя (Коллекция), и я не могу преобразовать в новое имя, и я не могу просто удалить данные пользователя. Итак, я действительно в тупике.

Цитата

Я пытался изменить oldObject перед созданием нового объекта, но вы не можете изменить oldObject при миграции.

Единственное правило состоит в том, что старые данные должны быть сохранены, я не могу просто уничтожить область пользователя здесь.

Спасибо за любую помощь в этом. Это очень ценится.


person Dan Morrow    schedule 20.12.2017    source источник
comment
Что произойдет, если вы не настроите блок миграции, а просто попытаетесь позволить Realm выполнять свою работу? Кстати, я надеюсь, что это был хороший урок о том, почему бы не называть ваши типы, используя имя, которое уже используется встроенным типом.   -  person Dávid Pásztor    schedule 21.12.2017
comment
Что ж, в то время я был новичком в Swift (коду несколько лет) и не понимал, что существует класс Collection. А поскольку все скомпилировано и построено отлично, это не имело значения. Нет, пока я не попытался добавить в смесь macOS.   -  person Dan Morrow    schedule 21.12.2017
comment
извините, Realm не может просто выполнять свою работу. Если бы это было так, я бы не писал этот код миграции.   -  person Dan Morrow    schedule 21.12.2017
comment
Я видел, как люди несколько раз писали блоки миграции для случаев, которые можно было бы обработать с помощью автоматической миграции, поэтому я спросил :) Вы получаете ту же ошибку при автоматической миграции, что и с вашим текущим блоком миграции?   -  person Dávid Pásztor    schedule 21.12.2017


Ответы (1)


Прошлой ночью у меня была очень похожая проблема. У меня было несколько классов Realm, которые я хотел переименовать, и у одного из них было свойство List, относящееся ко второму классу. Итак, единственная разница по сравнению с вашей проблемой в том, что я также переименовал класс ItemObject.

Вот как я это сделал:

  1. Сначала перенесите свой класс Collection, создав SpecialCollection.
  2. Во время миграции просмотрите список Collection, создайте новый SpecialItemObject для каждого ItemObject и добавьте его в новый список.
  3. Удалите каждый ItemObject.
  4. Теперь перечислите все ItemObject, оставшиеся в области, и создайте новый SpecialItemObject и сопоставьте его значения. Причина в том, что в вашей области может быть другой ItemObject, не связанный со списком.
  5. Удалите все оставшиеся ItemObject.

migration.enumerateObjects(ofType: "Collection")
{ (oldObject, newObject) in
    let specialCollection = migration.create(SpecialCollection.className())
    specialCollection["name"] = oldObject!["name"]
    specialCollection["url"] = oldObject!["url"]

    if let oldItems = oldObject!["items"] as? List<MigrationObject>,
       let newItems = specialCollection["items"] as? List<MigrationObject>
    {
        for oldItem in oldItems
        {
            let newItem = migration.create(SpecialItemObject.className())
            newItem["name"] = oldItem["name"]  // You didn't specify what was in your ItemObject so this example just assumes a name property.
            newItems.append(newItem)
            migration.delete(oldItem)
        }
    }
}
migration.deleteData(forType: "Collection")

// Now migrate any remaining ItemObject objects that were not part of a Collection.
migration.enumerateObjects(ofType: "ItemObject")
{ (oldObject, newObject) in
    let newItem = migration.create(SpecialItemObject.className())
    newItem["name"] = oldItem["name"]
}

// Now let's be sure we'll have no further ItemObject in our entire Realm.
migration.deleteData(forType: "ItemObject") 

Вот как я решил это для себя прошлой ночью, почти ничего не обнаружив почти ничего о большей части этого в области какао в GitHub, на SO или в другом месте. Приведенный выше пример отличается от того, что вы просили, только тем, что вы не просили переименовать свой класс ItemObject. Вы можете попробовать просто создать новые объекты ItemObject и сопоставить их свойства так же, как я показываю в моем примере. Не понимаю, почему это не сработает. Я привел свой пример, как именно я решил свою проблему, так как вчера вечером я протестировал несколько миграций, чтобы доказать, что это надежно.

Поскольку вашему вопросу почти 5 месяцев, я просто отправляю этот ответ для потомков. Надеюсь, это кому-то поможет!

Протестировано с Realm 3.3.2 на iOS 11.3 sim / Xcode 9.3 / Swift 4.1

person Smartcat    schedule 10.05.2018
comment
Если вы создаете со значением, вы можете пропустить присвоение свойств. Однако любые свойства объекта будут автоматически воссозданы, поэтому, если SpecialItemObject содержит отношения областей, это может быть нецелесообразно. - person Chris Douglass; 29.04.2020