肇鑫的技术博客

业精于勤,荒于嬉

Realm模型升级(一)

所谓模型升级,是指数据库存储的数据,随着需求的变化,产生了格式的改变。这个时候,由于数据库里有数据,直接修改模型并运行程序,程序就会崩溃,原因是模型发生了变化。

Realm本身提供了模型升级的功能。官方文档的实例也简单易懂。

https://realm.io/docs/swift/latest#migrations

不过,今天我遇到一个特殊情况,发现需要在升级的时候使用List对象,是不能直接转换的,摸索之后找到解决方案。先看问题。

问题

已有代码

class Item:Object {
    @objc dynamic var title = ""
    let records = List<Record>()
    
    override class func primaryKey() -> String? {
        return "title"
    }
}

class Record:Object {
    @objc dynamic var id:Int = 1
    @objc dynamic var addedDate:Date = Date()
}

新需求需要在Item中添加一个新的属性@objc dynamic var addedDate:Date = Date()

class Item:Object {
    @objc dynamic var title = ""
    @objc dynamic var addedDate:Date = Date()
    let records = List<Record>()
    
    override class func primaryKey() -> String? {
        return "title"
    }
}

class Record:Object {
    @objc dynamic var id:Int = 1
    @objc dynamic var addedDate:Date = Date()
}

升级代码如下:

// update realm
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: 1,
    
    // 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 < 1) {
            // Nothing to do!
            // Realm will automatically detect new properties and removed properties
            // And will update the schema on disk automatically
            
            migration.enumerateObjects(ofType: Item.className()) { oldObject, newObject in
                newObject!["addedDate"] = (oldObject!["records"] as! List<Record>).first?.addedDate ?? Date()
            }
        }
})

// 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
let _ = try! Realm()

运行时程序出错,提示不能将List<DynamicObject>转换为List<Record>

解决

经过查找资料发现,需要将其转化为List<MigrationObject。代码如下。究其原因,应该是Realm实例还没有创建,任何Realm的对象都是不可用的。(RecordObject子类)

// update realm
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: 1,
    
    // 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 < 1) {
            // Nothing to do!
            // Realm will automatically detect new properties and removed properties
            // And will update the schema on disk automatically
            
            migration.enumerateObjects(ofType: Item.className()) { oldObject, newObject in
                newObject!["addedDate"] = (oldObject!["records"] as? List<MigrationObject>)?.first?["addedDate"] as? Date ?? Date()
            }
        }
})

// 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
let _ = try! Realm()

相关文章

Realm模型升级(二)