Core Data Migration--Core Data輕量級(jí)遷移

  • 背景:

    • 我們的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í)候哼勇。比如


      CoreData里面的Model
  • 當(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ò)院溺。安裝不了


      **reason = "The model used to open the store is incompatible with the one used to create the store";**
  • 而遇上這樣的問(wèn)題肯定不行,用戶用不了你就掛了磅轻。所以我們要做版本的數(shù)據(jù)遷移




  • 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)題
  • 創(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.
    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è))

Add Model Version
Model Virsion
  • 名字可以隨便起苇瓣,但是建議最好叫xxxV2/3/...便于區(qū)分尉间,因?yàn)槟忝窟w移或者增加Model一次就產(chǎn)生了一次新的Model Schema.每次都會(huì)變的哦
  • 然后我們就要Model Virsion2成為我們的可用的Model.選中Core Data model。然后:
ModelV2成為最新的可用的Model
對(duì)應(yīng)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)證



蘋果產(chǎn)品對(duì)應(yīng)架構(gòu)
  • 在項(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 Guruhttp://club.fir.im/topic/54daf35374c4c85e73e4aaba)。
    發(fā)現(xiàn)是自己有一個(gè)必須用到的參數(shù)id的問(wèn)題
曾經(jīng)我的id一直是Int64
  • 這里的問(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ù)了
吐槽:Swift編譯時(shí)間好長(zhǎng)。疫衩。硅蹦。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子童芹,更是在濱河造成了極大的恐慌涮瞻,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件假褪,死亡現(xiàn)場(chǎng)離奇詭異署咽,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)嗜价,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門艇抠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人久锥,你說(shuō)我怎么就攤上這事家淤。” “怎么了瑟由?”我有些...
    開封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵絮重,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我歹苦,道長(zhǎng)青伤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任殴瘦,我火速辦了婚禮狠角,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蚪腋。我一直安慰自己丰歌,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開白布屉凯。 她就那樣靜靜地躺著立帖,像睡著了一般。 火紅的嫁衣襯著肌膚如雪悠砚。 梳的紋絲不亂的頭發(fā)上晓勇,一...
    開封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音灌旧,去河邊找鬼绑咱。 笑死,一個(gè)胖子當(dāng)著我的面吹牛枢泰,可吹牛的內(nèi)容都是我干的羡玛。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼宗苍,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起讳窟,我...
    開封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤让歼,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后丽啡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體谋右,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年补箍,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了改执。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡坑雅,死狀恐怖辈挂,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情裹粤,我是刑警寧澤终蒂,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站遥诉,受9級(jí)特大地震影響拇泣,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜矮锈,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一霉翔、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧苞笨,春花似錦债朵、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至猜丹,卻和暖如春芝加,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背射窒。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工藏杖, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人脉顿。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓蝌麸,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親艾疟。 傳聞我的和親對(duì)象是個(gè)殘疾皇子来吩,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容