从一个List执行Realm迁移到另一个更新属性值

时间:2017-02-23 00:34:03

标签: ios swift realm realm-migration

我试图计算我的清单中有多少张卡是相同的,并用计数编号更新新的数量属性

  

例如:

     

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

     

分配到临时列表

     

var tempList = List()

     

CardObject1(将数量属性更新为1)
  CardObject2(将数量属性更新为3)
  CardObject3(将数量属性更新为2)

     

tempList = [CardObject1,CardObject2,CardObject3]

     

分配回newObject![" list"]更新/迁移的列表

     

newObject![" list"] = newList

newList.index(of:card)

崩溃
  

*由于未捕获的异常终止应用' RLMException',原因:'对象类型' CardDTO'与RLMArray类型不匹配' DynamicObject'。'   * 首先抛出调用堆栈:

的信息:

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

1 个答案:

答案 0 :(得分:0)

Realm迁移块(及其动态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>属性是错误的。