执行从一个列表到另一个更新 属性 值的领域迁移

Perform Realm migration from one List to another updating property value

我正在尝试计算我的列表中有多少张卡片是相等的,并使用计数

更新新数量 属性

eg:

newObject!["list"] = [CardObject1, CardObject2, CardObject2, CardObject2, CardObject3, CardObject3]

Assign to temporary list

var tempList = List()

CardObject1 (Update quantity property to 1)
CardObject2 (Update quantity property to 3)
CardObject3 (Update quantity property to 2)

tempList = [CardObject1, CardObject2, CardObject3]

Assign back to newObject!["list"] the updated/migrated list

newObject!["list"] = newList

崩溃在 newList.index(来自:卡)

* Terminating app due to uncaught exception 'RLMException', reason: 'Object type 'CardDTO' does not match RLMArray type 'DynamicObject'.' * First throw call stack:

信息:

DeckDTO.swift

class DeckDTO: Object {
dynamic var id = NSUUID().uuidString
dynamic var name = ""
var list = List<CardDTO>()

  override class func primaryKey() -> String {
    return "id"
  }
}

CardDTO.swift

class CardDTO: Object, Mappable {

// Other properties
dynamic var id = NSUUID().uuidString
dynamic var quantity: Int = 1
// Other properties

 required convenience public init?(map: Map) {
    self.init()
    mapping(map: map)
 }

 func mapping(map: Map) {
    //Map all my properties
 }

 override class func primaryKey() -> String {
    return "id"
 }
}

我正在尝试什么

if oldSchemaVersion < 2 {
  migration.enumerateObjects(ofType: CardDTO.className()) { oldObject, newObject in
    newObject!["quantity"] = 1
  }

  migration.enumerateObjects(ofType: DeckDTO.className()) { oldObject, newObject in
    var newList = List<DynamicObject>()
    let oldList = newObject!["list"] as! List<DynamicObject>
    for card in oldList {
        if let i = newList.index(of: card), i >= 0 {
            newList[i] = (newList[i] as! CardDTO).quantity += 1 //some how do quantity++
            print("increment quantity")
        } else {
            newList.append(card)
        }
    }
    newObject!["list"] = newList
  }
}

领域迁移块(及其动态 API)并不真正适合您的特定用例。 index(of:)append() 都不能正确用于动态对象。

我对解决此问题的建议是在迁移块中简单地将 quantity 属性设置为 1,然后设置一个布尔标志,指示您需要执行牌组更新。然后,在您执行任何其他操作之前(可能在 application(_: didFinishLaunchingWithOptions:) 中),打开 Realm 并检查该标志。如果设置了该标志,则您可以打开 Realm 并使用普通 Realm API.

执行迁移

这是一些示例代码:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // Get the configuration and set the migration block on it
    var config = Realm.Configuration.defaultConfiguration
    config.schemaVersion = 2
    var needsMigrationToV2 = false

    config.migrationBlock = { migration, oldSchemaVersion in
        if oldSchemaVersion < 2 {
            migration.enumerateObjects(ofType: CardDTO.className()) { oldObject, newObject in
                newObject!["quantity"] = 1
            }
            needsMigrationToV2 = true
        }
    }
    let realm = try! Realm(configuration: config)
    // Run the rest of the migration using the typed API
    if needsMigrationToV2 {
        let allDecks = realm.objects(DeckDTO.self)
        try! realm.write {
            for deck in allDecks {
                var uniqueCards : [CardDTO] = []
                for card in deck.list {
                    if uniqueCards.contains(card) {
                        card.quantity += 1
                    } else {
                        uniqueCards.append(card)
                    }
                }
                deck.list.removeAll()
                deck.list.append(objectsIn: uniqueCards)
            }
        }
    }
    return true
}

还有一件事要注意,List<T> 属性应该声明为 let,而不是 var,因为重新分配给 List<T> 属性 是一个错误。