Core Data Migration--Core Data轻量级迁移

  • 背景:

    • 我们的APP只需要在用户登录的时候存储一些关键的数据,数据量不大。其余数据在线请求就行,也没有涉及大量的数据存储,用Core Data 还挺方便的
    • 当我要发布企业1.2版本的时候,发现因为用了CoreData进行数据的存储,当我修改了里面的Model的时候。比如


      CoreData里面的Model
  • 当我添加或者修改一个字段或者是添加另外一个model的时候。我们会遇到两个问题

    • 1.运行到真机:会报错,需要卸载APP后再运行重装
    • 2.发布版本后,你无法覆盖安装而且会出错。安装不了


      **reason = "The model used to open the store is incompatible with the one used to create the store";**
  • 而遇上这样的问题肯定不行,用户用不了你就挂了。所以我们要做版本的数据迁移




  • 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.
    • 也就是我们上面遇上的问题:当你在swift中使用了CoreData,CoreData是需要一个始终如一的模式。如果你修改了添加或者移除了任何一个实体属性或者修改了类型。就会造成冲突。就会导致运行的时候你的APP崩溃,或者别人在AppStore上下载你的APP后直接崩溃闪退,这是很严重的问题,丢失用户可能是致命问题
  • 创建一个迁移Migration--Create A Migration
    • 没创建迁移前Xcode会在AppDelegate中为我们自动创建下面的代码。但是Xcode并没有给出任何的可选的迁移。但是它有一个persistentStoreCoordinator。它是专门负责迁移的发生。我们只需要关注options。它是一个字典,是一个迁移字典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 {
  • 创建迁移后是:
    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
    }()
  • 也就是说,我们添加了:
            let mOptions = [NSMigratePersistentStoresAutomaticallyOption: true,
                            NSInferMappingModelAutomaticallyOption: true]
            try coordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: mOptions)
  • 这样基础的操作,是让我们的Core Data去尝试让我们的Models在不同的版本之间自动合并以及映射

  • 但是这样还是不够,我们还需要接下来的操作

  • 添加一个Model版本--Add a Model Version

  • 先要选上你的Core Data model,然后在工程的导航栏部分-->Editor-->Add Model Version(不选上,不会出现这个)

Add Model Version
Model Virsion
  • 名字可以随便起,但是建议最好叫xxxV2/3/...便于区分,因为你每迁移或者增加Model一次就产生了一次新的Model Schema.每次都会变的哦
  • 然后我们就要Model Virsion2成为我们的可用的Model.选中Core Data model。然后:
ModelV2成为最新的可用的Model
对应Model文件中修改一下
  • 这样你就可以在MedelV2中修改你想修改的了,APP运行和发布后也就不会出错了

  • 重要的几点:

    • 1.设置好options
    • 2.添加新的Model Virsion
    • 3.选好新的Model Virsion
  • 猜测的几点

    • 1.每次大的修改Model都要添加新的Model Virsion.版本不停往上
    • 2.修改哪怕是退回去的时候,也最好是新建一个新的Model Virsion,删除不想要的
    • 3.有些还需要我去继续验证



苹果产品对应架构
  • 在项目中遇上了一个Swift中的一个坑:当APP发版后,有用户发现他的iPhone5和5c装上APP点击登录后直接崩溃闪退。其余的手机没有问题。首先我以为是我们SDK支持的架构不支持ARMv7s,但是问清楚后发现是支持4s往上的。所以问题肯定出现在自己的程序中。查看崩溃日志(查看崩溃日志的工具Log Guruhttp://club.fir.im/topic/54daf35374c4c85e73e4aaba)。
    发现是自己有一个必须用到的参数id的问题
曾经我的id一直是Int64
  • 这里的问题是:Swift是强语言,类型要求十分严格。我在Core Data里用了一个Integer64,然后Swift代码里面写的是Int。最后导致程序不能安装(iPhone5和5c的CPU是32位的,所以要用Int32向上兼容。这里就用到了上面数据的迁移将它改成Int32,也不会出问题了)如果是已经上架AppStore的话,5和5c用户就等下一个版本吧。。。我也就分分钟去财务了
吐槽:Swift编译时间好长。。。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,710评论 4 376
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,839评论 2 308
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 112,295评论 0 255
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,776评论 0 223
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,198评论 3 297
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,074评论 1 226
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,200评论 2 322
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,986评论 0 214
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,733评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,877评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,348评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,675评论 3 265
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,393评论 3 246
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,209评论 0 9
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,996评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,212评论 2 287
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 36,003评论 2 280

推荐阅读更多精彩内容