核心数据轻量级迁移在应用程序更新后崩溃

两天前我发布了应用程序。 根据AppStore的反馈和itunesconnect发布的崩溃报告,发布中有很多崩溃。 但是,不是100%的用户受到了影响,也许只有30%。

我读过崩溃日志,看到一个问题。 它正在数据库迁移过程中崩溃。 我使用轻量级数据库迁移。 通常我会非常仔细地添加新的datamodel版本。 即使在每个发行版之前,我都安装了以前版本的应用程序,使用它一段时间,然后才安装最新版本。 那么这次呢。

我浏览了两个数据模型(之前和现在)。 添加:

1)新实体(轻量级迁移是可以的)
2)现有实体内的新字段。 他们都是可选的。 (确定轻量级迁移)
3)我做了可选的AND索引的现有实体中的一个新领域。 (好?)

没有现有的字段和实体被重命名。

我做错了什么?

堆栈跟踪:

Thread 0 name: Dispatch queue: com.apple.main-thread Thread 0: 0 libsystem_kernel.dylib 0x352f439c pread + 20 1 libsqlite3.dylib 0x30d2d632 unixRead 2 libsqlite3.dylib 0x30d4221a readDbPage 3 libsqlite3.dylib 0x30d41156 sqlite3PagerAcquire 4 libsqlite3.dylib 0x30d583be moveToChild 5 libsqlite3.dylib 0x30d8e0e8 moveToLeftmost 6 libsqlite3.dylib 0x30d59582 sqlite3BtreeNext 7 libsqlite3.dylib 0x30d54328 sqlite3VdbeExec 8 libsqlite3.dylib 0x30d4f6c2 sqlite3_step 9 CoreData 0x329e8e2e _execute 10 CoreData 0x329e8d64 -[NSSQLiteConnection execute] 11 CoreData 0x32a8bd54 -[NSSQLConnection prepareAndExecuteSQLStatement:] 12 CoreData 0x32add63c -[_NSSQLiteStoreMigrator performMigration:] 13 CoreData 0x32ad42b8 -[NSSQLiteInPlaceMigrationManager migrateStoreFromURL:type:options:withMappingModel:toDestinationURL:destinationType:destinationOptions:error:] 14 CoreData 0x32a79c02 -[NSMigrationManager migrateStoreFromURL:type:options:withMappingModel:toDestinationURL:destinationType:destinationOptions:error:] 15 CoreData 0x32ac5bf4 -[NSStoreMigrationPolicy(InternalMethods) migrateStoreAtURL:toURL:storeType:options:withManager:error:] 16 CoreData 0x32ac519c -[NSStoreMigrationPolicy migrateStoreAtURL:withManager:metadata:options:error:] 17 CoreData 0x32ac6b58 -[NSStoreMigrationPolicy(InternalMethods) _gatherDataAndPerformMigration:] 

那些用户不止一个.xcversion的机会呢? 核心数据不会“链接”你的升级。 所以如果你有V1,V2和V3,V3成为当前版本,V1中的任何人都不能升级。 有可能在你自己的代码中添加“V1”到“V2”,然后“V2”到“V3”。 我相信Marcus Zarra的“核心数据”一书有这样的例子代码。

如果这是V3的数据模型,您还需要包含V1和V2 xcdatamodel与发货的应用程序,以防您的一些用户仍然在V1,并从未升级到V2。 这听起来像你有一个V1的数据模型,但没有包括它 – 但我不知道,你可能只是在谈论你已经做了这些其他应用程序。

另外,您会注意到Xcode不pipe理数据模型的有序列表,您只能select哪一个是当前的数据模型。 它不能自动升级V1 – > …-> Vm-> Vn,因为它不知道旧版本之间的顺序,只是需要成为Vn才能工作。 尝试用文本编辑器在xcdatamodeld包中查找。

如果您完全依赖核心数据提供的行为,则无论是推断的映射模型,还是包括显式映射模型,您的所有先前版本都必须能够直接迁移到最新版本:从V1-> Vn,V2 Vn,…,Vm-> Vn。 这就是为什么有些人编写自己的代码来pipe理这个。

我相信这正是斯科特在他的回答中所描述的。

在开发我们的应用程序的过程中,我们创build了大约6个版本的数据模型(在将v1发布到App Store之前,我们只有最新的版本)。 我发现编写unit testing非常有帮助,这些unit testing证实Core Data 可以创build推断的映射模型,并且轻量级的迁移也可以工作。

去做这个:

 NSURL *sourceURL = /* exercise for reader */, *destinationURL = /* exercise */; NSManagedObjectModel *source = [[NSManagedObjectModel alloc] initWithContentsOfURL:sourceURL]; NSManagedObjectModel *destination = [[NSManagedObjectModel alloc] initWithContentsOfURL:sourceURL]; NSError *mappingError; NSMappingModel *inferred = [NSMappingModel inferredMappingModelForSourceModel:source destinationModel:destination error:&mappingError]; 

在这个代码块的末尾,你可以声明推断!= nil,如果它是零,你可以通过检查mappingError打印一些有用的信息。

您可能会发现这有助于debugging您的问题。 您可能会将重复部分移动到一个函数中,该函数需要两个string,一个旧数据模型的文件名和最新的文件名。