接上一篇,這次筆記「半自動」模式,計畫如下:
1. 建立一 Use Core Data
專案
2. 建立 Person
Entity
3. 在 Person
建立 fullname
欄位
4. 簡單的先在自動產生的 ViewController 中加入一比資料,以空格分開 firstname 和 lastname
5. 首次執行並確定資料新增
6. 刪除新增資料的程式碼
7. 建立一新版本的 Data Model:Model2
8. 在 Model2 中將 fullname
欄位刪除,並加入 firstname
和 lastname
欄位
9. 建立 Model1 到 Model2 的 Mapping File
10. 建立 fullname
欄位的 Migration Policy File:將 fullname
依照空格拆為 firstname
及 lastname
11. 將 Migration Policy 設定給 Mapping File
12. 設定 options 啟動 NSMigratePersistentStoresAutomaticallyOption
13. 第二次執行並確認 .sqlite
schema 和資料有成功變更
1 ~ 3
專案名稱為:CoreDataManualMappingFile,創建時勾選 Use Core Data
選項
4
新增一筆資料內容為 Michael Jack
import UIKit
import CoreData
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let app = UIApplication.sharedApplication().delegate as? AppDelegate {
let newPerson: NSManagedObject = NSEntityDescription.insertNewObjectForEntityForName("Person", inManagedObjectContext: app.managedObjectContext)
newPerson.setValue("Michael Jack", forKey: "fullname")
app.saveContext()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
5 ~ 6
在 AppDelegate.swift
中 lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator
裡將 url
print 出來,已確認資料是否建立
let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("SingleViewCoreData.sqlite")
print(url)
print 結果如以下:角括號中為個電腦不同的名稱 /Users/<user>/Library/Developer/CoreSimulator/Devices/<UUID>/data/Containers/Data/Application/<UUID>/Documents/SingleViewCoreData.sqlite
用 SQLite Browser 開啟該檔案,可以看到目前資料庫的 schema 和實際上的資料。
確認資料有新增後,刪除 4. 中的程式碼。
7 ~ 8
建立一個新的 Data Model Version:DataModel2,將預設 fullname
刪除,並加入 firstname
、lastname
9
10
新增Person1ToPerson2類別,繼承NSEntityMigrationPolicy並改寫createDestinationInstancesForSourceInstance方法
- 從
source instance
中拿到原始資料
let fullname = sInstance.valueForKey("name")! as! String
- 使用新的 data model 獲得新 data model 的 instance
let destinationInstance: NSManagedObject = NSEntityDescription.insertNewObjectForEntityForName(mapping.destinationEntityName!, inManagedObjectContext: manager.destinationContext)
- 解析原始資料,並將結果設定至新的 instance
let fullnameArr = fullname.componentsSeparatedByString(" ")
destinationInstance.setValue(fullnameArr[0], forKey: "firstname")
destinationInstance.setValue(fullnameArr[1], forKey: "lastname")
- 呼叫 manager 將新舊資料做聯繫
manager.associateSourceInstance(sInstance, withDestinationInstance: destinationInstance, forEntityMapping: mapping)
完整類別程式碼
import CoreData
class Person1ToPerson2: NSEntityMigrationPolicy {
override func createDestinationInstancesForSourceInstance(sInstance: NSManagedObject, entityMapping mapping: NSEntityMapping, manager: NSMigrationManager) throws {
let destinationInstance: NSManagedObject = NSEntityDescription.insertNewObjectForEntityForName(mapping.destinationEntityName!, inManagedObjectContext: manager.destinationContext)
// 新的 data model entity
let fullname = sInstance.valueForKey("fullname")! as! String
// 從原始資料庫獲得資料
let fullnameArr = fullname.componentsSeparatedByString(" ")
// 依照空格拆成字串陣列
destinationInstance.setValue(fullnameArr[0], forKey: "firstname")
destinationInstance.setValue(fullnameArr[1], forKey: "lastname")
manager.associateSourceInstance(sInstance, withDestinationInstance: destinationInstance, forEntityMapping: mapping)
}
}
11
選擇 Mapping File –> 點選 PersonToPerson –> 在 Custom Policy 中輸入 CoreDataManualMappingFile.Person1ToPerson2
ps. 在此筆記製作時,如果沒有輸入專案名稱,會找不到 Mapping Policy File
12 ~ 13
先將 Model Version 設定為 Model2
在 AppDelegate 中設定 coordinator.addPersistentStoreWithType
增加啟用 NSMigratePersistentStoresAutomaticallyOption
coordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: [
NSMigratePersistentStoresAutomaticallyOption: true
])
因為 coordinator 在 AppDelegate 中設定為 lazy
,所以在 ViewDidLoad
中該為直接將 managedObjectContext
print 出來,強制執行並 print url
if let app = UIApplication.sharedApplication().delegate as? AppDelegate {
print(app.managedObjectContext)
}
執行後再檢視 .sqlite
檔案
可以看到資料庫 schema 已經改為 DataModel2 的欄位配置,並且欄位也依照設定的 Policy 做轉換
結論
半自動模式就是自己定義 Mapping File 和 Migration Policy,這樣想怎麼轉就可以怎麼轉,但是這樣還是有不足的地方,像是如果有 3 個版本的 data model,那就會需要 V1 –> V2、V2 –> V3、V1 –> V3,3 個 轉換結構 ( Mapping File 與 Migration Policy )。因為無法確定用戶端何時更新 APP,所以必須要設想如果用戶端沒有更新到 V2,但是後來更新時,APP Store 上的 data model 版本已經是 V3,那這樣就會造成資料錯誤,所以需要製作 V1 –> V3 的轉換結構。但是這樣又會造成另一個問題,當有 4 個 data model 版本時,那就會需要 6 個 轉換結構,隨著版本越來越多會越來越難維護也越來越難懂。
v:版本數量
n:Mapping File 數量
沒有留言:
張貼留言