-
背景:
- 我們的APP只需要在用戶登錄的時(shí)候存儲(chǔ)一些關(guān)鍵的數(shù)據(jù)钩杰,數(shù)據(jù)量不大。其余數(shù)據(jù)在線請(qǐng)求就行,也沒(méi)有涉及大量的數(shù)據(jù)存儲(chǔ),用Core Data 還挺方便的
-
當(dāng)我要發(fā)布企業(yè)1.2版本的時(shí)候烦磁,發(fā)現(xiàn)因?yàn)橛昧薈oreData進(jìn)行數(shù)據(jù)的存儲(chǔ),當(dāng)我修改了里面的Model的時(shí)候哼勇。比如
-
當(dāng)我添加或者修改一個(gè)字段或者是添加另外一個(gè)model的時(shí)候都伪。我們會(huì)遇到兩個(gè)問(wèn)題
- 1.運(yùn)行到真機(jī):會(huì)報(bào)錯(cuò),需要卸載APP后再運(yùn)行重裝
-
2.發(fā)布版本后猴蹂,你無(wú)法覆蓋安裝而且會(huì)出錯(cuò)院溺。安裝不了
-
而遇上這樣的問(wèn)題肯定不行,用戶用不了你就掛了磅轻。所以我們要做版本的
數(shù)據(jù)遷移
- 但是這種情況沒(méi)有接觸過(guò)就只能Google了
- 參考地址:http://jamesonquave.com/blog/core-data-migrations-swift-tutorial/
-
Why Make Core Data Migrations?
However there is a problem. Core Data expects a consistent schema. Meaning that if we add or remove entities, attributes, or change their types, it will cause a conflict. This means that if you:1) Store some data inside of an app using a set schema. For example a Model named LogItem with a title(String) attribute.2) Change any of the schema. For example add a new full title attribute to become ‘fullTitle’.3) Run the app again
There will be a conflict, and the app will do a hard crash. This includes anyone who has downloaded your app from the app store! Not only that, if you change the text attribute, and you don’t perform any kind of migration, you will be risking losing user’s data. If you want people to uninstall your app, this is a fantastic way to make that happen.- 也就是我們上面遇上的問(wèn)題:當(dāng)你在swift中使用了CoreData,CoreData是需要一個(gè)始終如一的模式逐虚。如果你
修改了
聋溜,添加
或者移除
了任何一個(gè)實(shí)體
,屬性
或者修改了類型
叭爱。就會(huì)造成沖突
撮躁。就會(huì)導(dǎo)致運(yùn)行
的時(shí)候你的APP崩潰
,或者別人在AppStore上下載你的APP后直接崩潰閃退买雾,這是很嚴(yán)重的問(wèn)題把曼,丟失用戶可能是致命問(wèn)題
- 也就是我們上面遇上的問(wèn)題:當(dāng)你在swift中使用了CoreData,CoreData是需要一個(gè)始終如一的模式逐虚。如果你
- 創(chuàng)建一個(gè)
遷移Migration
--Create A Migration- 沒(méi)創(chuàng)建遷移前Xcode會(huì)在AppDelegate中為我們自動(dòng)創(chuàng)建下面的代碼杨帽。但是Xcode并沒(méi)有給出任何的
可選的遷移
。但是它有一個(gè)persistentStoreCoordinator
嗤军。它是專門負(fù)責(zé)遷移的發(fā)生注盈。我們只需要關(guān)注options
。它是一個(gè)字典
叙赚,是一個(gè)遷移字典Migrations Options
- NSMigratePersistentStoresAutomaticallyOption sounds pretty nice. Automatic migration? Sign me up!
- NSInferMappingModelAutomaticallyOption will create the mapping model, while
- NSMigratePersistentStoresAutomaticallyOption will perform the migration.
- 沒(méi)創(chuàng)建遷移前Xcode會(huì)在AppDelegate中為我們自動(dòng)創(chuàng)建下面的代碼杨帽。但是Xcode并沒(méi)有給出任何的
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
// The persistent store coordinator for the application. This implementation creates and returns a coordinator, having added the store for the application to it. This property is optional since there are legitimate error conditions that could cause the creation of the store to fail.
// Create the coordinator and store
let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("SingleViewCoreData.sqlite")
var failureReason = "There was an error creating or loading the application's saved data."
do {
try coordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: nil)
} catch {
// Report any error we got.
var dict = [String: AnyObject]()
dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
dict[NSLocalizedFailureReasonErrorKey] = failureReason
dict[NSUnderlyingErrorKey] = error as NSError
let wrappedError = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)
// Replace this with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog("Unresolved error \(wrappedError), \(wrappedError.userInfo)")
abort()
}
return coordinator
}()
- 所以我們添加
let mOptions = [NSMigratePersistentStoresAutomaticallyOption: true,
NSInferMappingModelAutomaticallyOption: true]
if coordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: mOptions, error: &error) == nil {
- 創(chuàng)建遷移后是:
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
// The persistent store coordinator for the application. This implementation creates and returns a coordinator, having added the store for the application to it. This property is optional since there are legitimate error conditions that could cause the creation of the store to fail.
// Create the coordinator and store
let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("SingleViewCoreData.sqlite")
var failureReason = "There was an error creating or loading the application's saved data."
do {
let mOptions = [NSMigratePersistentStoresAutomaticallyOption: true,
NSInferMappingModelAutomaticallyOption: true]
try coordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: mOptions)
} catch {
// Report any error we got.
var dict = [String: AnyObject]()
dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
dict[NSLocalizedFailureReasonErrorKey] = failureReason
dict[NSUnderlyingErrorKey] = error as NSError
let wrappedError = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)
// Replace this with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog("Unresolved error \(wrappedError), \(wrappedError.userInfo)")
abort()
}
return coordinator
}()
- 也就是說(shuō)老客,我們添加了:
let mOptions = [NSMigratePersistentStoresAutomaticallyOption: true,
NSInferMappingModelAutomaticallyOption: true]
try coordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: mOptions)
這樣基礎(chǔ)的操作,是讓我們的Core Data去嘗試讓我們的Models在不同的版本之間自動(dòng)合并以及映射
但是這樣還是不夠震叮,我們還需要接下來(lái)的操作
添加一個(gè)Model版本--Add a Model Version
先要選上你的Core Data model胧砰,然后在工程的導(dǎo)航欄部分-->Editor-->Add Model Version(不選上,不會(huì)出現(xiàn)這個(gè))
- 名字可以隨便起苇瓣,但是建議最好叫xxxV2/3/...便于區(qū)分尉间,因?yàn)槟忝窟w移或者增加Model一次就產(chǎn)生了一次新的Model Schema.每次都會(huì)變的哦
- 然后我們就要Model Virsion2成為我們的可用的Model.選中Core Data model。然后:
這樣你就可以在MedelV2中修改你想修改的了击罪,APP運(yùn)行和發(fā)布后也就不會(huì)出錯(cuò)了
-
重要的幾點(diǎn):
- 1.設(shè)置好options
- 2.添加新的Model Virsion
- 3.選好新的Model Virsion
-
猜測(cè)的幾點(diǎn)
- 1.每次大的修改Model都要添加新的Model Virsion.版本不停往上
- 2.修改哪怕是退回去的時(shí)候哲嘲,也最好是新建一個(gè)新的Model Virsion,刪除不想要的
- 3.有些還需要我去繼續(xù)驗(yàn)證
- 在項(xiàng)目中遇上了一個(gè)Swift中的一個(gè)坑:當(dāng)APP發(fā)版后外邓,有用戶發(fā)現(xiàn)他的iPhone5和5c裝上APP點(diǎn)擊登錄后直接崩潰閃退撤蚊。其余的手機(jī)沒(méi)有問(wèn)題。首先我以為是我們SDK支持的架構(gòu)不支持ARMv7s,但是問(wèn)清楚后發(fā)現(xiàn)是支持4s往上的损话。所以問(wèn)題肯定出現(xiàn)在自己的程序中侦啸。查看崩潰日志(查看崩潰日志的工具Log Guru:http://club.fir.im/topic/54daf35374c4c85e73e4aaba)。
發(fā)現(xiàn)是自己有一個(gè)必須用到的參數(shù)id的問(wèn)題
- 這里的問(wèn)題是:Swift是強(qiáng)語(yǔ)言丧枪,類型要求十分嚴(yán)格光涂。我在Core Data里用了一個(gè)Integer64,然后Swift代碼里面寫的是Int拧烦。最后導(dǎo)致程序不能安裝(iPhone5和5c的CPU是32位的忘闻,所以要用Int32向上兼容。這里就用到了上面數(shù)據(jù)的遷移將它改成Int32恋博,也不會(huì)出問(wèn)題了)如果是已經(jīng)上架AppStore的話齐佳,5和5c用戶就等下一個(gè)版本吧。债沮。炼吴。我也就分分鐘去財(cái)務(wù)了