Realm模型升级(一)中讲了对象添加了新属性之后要如何升级。最近我又遇到了新的问题,要将对象改名。
新问题
因为业务的需要,必须将代码
class Item:Object {
static let calendar = Calendar(identifier: .gregorian)
@objc dynamic var title = ""
@objc dynamic var addedDate:Date = Date()
@objc dynamic var relatedItem:Item? = nil
let records = List<Record>()
override class func primaryKey() -> String? {
return "title"
}
}
class Record:Object {
static let dateFormatter:DateFormatter = {
let df = DateFormatter()
df.locale = Locale(identifier: "zh")
df.dateStyle = .medium
df.timeStyle = .none
return df
}()
@objc dynamic var id:Int = 1
@objc dynamic var addedDate:Date = Date()
}
更改为
class ACItem:Object {
static let calendar = Calendar(identifier: .gregorian)
@objc dynamic var title = ""
@objc dynamic var addedDate:Date = Date()
@objc dynamic var relatedItem:ACItem? = nil
let records = List<ACRecord>()
override class func primaryKey() -> String? {
return "title"
}
}
class ACRecord:Object {
static let dateFormatter:DateFormatter = {
let df = DateFormatter()
df.locale = Locale(identifier: "zh")
df.dateStyle = .medium
df.timeStyle = .none
return df
}()
@objc dynamic var id:Int = 1
@objc dynamic var addedDate:Date = Date()
}
即原来的类的名称之前,需要添加AC字样。更改了代码之后运行,发现数据不见了。
分析
打开数据库文件查看(如图)。原来,虽然代码中的类变了,但是数据库中的类还是原来的名字,需要手动迁移。
解决方案
23-39行,利用之前的Item
对象,生成ACItem
对象;利用Item
对象中的records
属性,生成ACRecord
对象。需要注意的事,因为代码中此时已经没有了Item
类和Record
类,我们没法使用Item.className()
,而只能直接使用"Item"
。
41-43行,删除掉旧数据。
let config:Realm.Configuration = {
// update realm
let config = Realm.Configuration(
fileURL: destinationURL,
// 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: 3,
// 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!
}
if (oldSchemaVersion < 2) {
// Nothing to do!
}
if (oldSchemaVersion < 3) {
migration.enumerateObjects(ofType: "Item") { (oldObject, _) in
let acItem = migration.create(ACItem.className())
acItem["title"] = oldObject!["title"]
acItem["addedDate"] = oldObject!["addedDate"]
guard let list = acItem["records"] as? List<MigrationObject>,
let oldList = oldObject!["records"] as? List<MigrationObject> else {
fatalError()
}
oldList.forEach { o in
let acRecord = migration.create(ACRecord.className())
acRecord["id"] = o["id"]
acRecord["addedDate"] = o["addedDate"]
list.append(acRecord)
}
}
// delete
migration.deleteData(forType: "Item")
migration.deleteData(forType: "Record")
}
})
return config
}()
总结
- 代码中对象的改名,意味着数据库中数据的迁移。
MigrationObjectEnumerateBlock
中的oldObject
,实际上一个词典,我们通过键来进行数据的查找。