我正在尝试对核心数据中的SQLite存储进行轻量级迁移。使用Xcode 4.3.1编写Lion10.7.3。
在我的NSPersistentDocument子类(AccountDocument)中,我重写了用于配置持久存储协调器的方法,以便它获得迁移的适当选项:
- (BOOL)configurePersistentStoreCoordinatorForURL:(NSURL *)url ofType:(NSString *)fileType modelConfiguration:(NSString *)configuration storeOptions:(NSDictionary *)storeOptions error:(NSError **)error
{
NSMutableDictionary *newStoreOptions;
if (storeOptions == nil) {
newStoreOptions = [NSMutableDictionary dictionary];
}
else {
newStoreOptions = [storeOptions mutableCopy];
}
[newStoreOptions setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
[newStoreOptions setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption];
BOOL result = [super configurePersistentStoreCoordinatorForURL:url ofType:fileType modelConfiguration:configuration storeOptions:newStoreOptions error:error];
return result;
}(感谢马尔科姆·克劳福德给出的提示:http://homepage.mac.com/mmalc/CocoaExamples/controllers.html)
当我运行这个应用程序时,它在NSPersistentDocument的-managedObjectModel实现中失败了
* thread #1: tid = 0x2703, 0x00007fff931d9350 libobjc.A.dylib`objc_msgSend_vtable13 + 16, stop reason = EXC_BAD_ACCESS (code=13, address=0x0)
frame #0: 0x00007fff931d9350 libobjc.A.dylib`objc_msgSend_vtable13 + 16
frame #1: 0x00007fff8935e975 CoreData`-[NSKnownKeysDictionary1 _setValues:retain:] + 197
frame #2: 0x00007fff8935f288 CoreData`_newReadModelFromBytes + 648
frame #3: 0x00007fff8935b93e CoreData`+[NSManagedObjectModel(_NSManagedObjectModelPrivateMethods) _newModelFromOptimizedEncoding:error:] + 9310
frame #4: 0x00007fff89359451 CoreData`-[NSManagedObjectModel(_NSManagedObjectModelPrivateMethods) initWithContentsOfOptimizedURL:] + 305
frame #5: 0x00007fff89358d7b CoreData`-[NSManagedObjectModel initWithContentsOfURL:] + 443
frame #6: 0x00007fff893e9519 CoreData`+[NSManagedObjectModel mergedModelFromBundles:] + 377
frame #7: 0x00007fff8ded7037 AppKit`-[NSPersistentDocument managedObjectModel] + 301
frame #8: 0x00007fff8ded70b3 AppKit`-[NSPersistentDocument managedObjectContext] + 75
frame #9: 0x00007fff8ded6e3f AppKit`-[NSPersistentDocument _persistentStoreCoordinator] + 18
frame #10: 0x00007fff8ded6b5d AppKit`-[NSPersistentDocument configurePersistentStoreCoordinatorForURL:ofType:modelConfiguration:storeOptions:error:] + 51
frame #11: 0x0000000100003193 BeanCounter`-[AccountDocument configurePersistentStoreCoordinatorForURL:ofType:modelConfiguration:storeOptions:error:] + 419 at AccountDocument.m:298从文档中可以看出,默认实现如下所示:
- (id)managedObjectModel
{
NSManagedObjectModel *result = [NSManagedObjectModel mergedModelFromBundles:nil];
return result;
}因此,为了更好地调试这个问题,我用以下方法重写了该方法:
- (id)managedObjectModel
{
NSBundle *bundle = [NSBundle mainBundle];
NSURL *url = [bundle URLForResource:@"AccountDocument2" withExtension:@"momd"];
NSManagedObjectModel *result = [[[NSManagedObjectModel alloc] initWithContentsOfURL:url] autorelease];
return result;
}(感谢杰夫LaMarche的想法:http://iphonedevelopment.blogspot.com/2009/09/core-data-migration-problems.html)
包和url都指向了我所期望的地方(并且我已经按照Marcus的建议清理了项目,所以在应用程序包使用mergedModelFromBundles:和版本控制(CoreData)中没有任何杂乱无章的.momd包)。然而,该应用程序继续崩溃,同时从url加载模型。
我已经检查过AccountDocument2.xcdatamodeld是一个包含两个版本控制模型的包: AccountDocument 2.xcdatamodel和(原始的) AccountDocument.xcdatamodel。文件属性中的"Versioned“弹出菜单设置为"AccountDocument 2”。
这两个模型之间唯一的区别是,一个实体有一个额外的(和可选的)属性。我的理解是,这为轻量级迁移模型提供了条件。
很明显,我做错了什么,但我不知道是什么。任何帮助都将是非常感谢的…
更新:
根据Martin的建议(以及对NSPersistentDocument文档的检查),我尝试为访问器使用以下代码:
- (id)managedObjectModel
{
static id sharedManagedObjectModel = nil;
if (sharedManagedObjectModel == nil) {
NSBundle *bundle = [NSBundle mainBundle];
NSURL *url = [bundle URLForResource:@"AccountDocument2" withExtension:@"momd"];
sharedManagedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:url];
}
return sharedManagedObjectModel;
}仍然崩溃的…
更新
在Twitter上提出了一些建议之后,我升级到Xcode 4.3.2,但问题依然存在。
RAGE更新
我刚刚在雪豹上使用Xcode 4.2创建了版本化的模型包(AccountDocument2.xcdatamodeld)。在构建和运行该应用程序之后,一切都如期而至。
然后,我将AccountDocument2.xcdatamodeld文件包带回Lion和Xcode 4.3.2。当我构建和运行应用程序时,它在加载.momd资源时会继续崩溃。是的,孩子们,这意味着Xcode 4.3.x和数据模型编译器(MOMC)是罪魁祸首。除了在雪豹上做我所有的构建之外,我找不到其他的解决办法。
我不是抨击Xcode 4的人,但当我们发现工具链无法从不透明规范(.mom和.xcdatamodeld)生成不透明文件(.xcdatamodel和.xcdatamodeld)时,很难对Mac和iOS工具的状态感到乐观。可笑的是,这些平台的核心组件破坏到了我无法在最新版本的SDK和developer工具上构建和运行我的应用程序的程度。
,这就是更新的
进一步证明这是Xcode 4.3.2中的(MOMC)的一个严重错误:如果我将Xcode 4.2创建的资源文件夹中的.momd包复制到我的项目中,并将它们作为复制文件构建阶段添加到构建中,则应用程序可以正常工作。
我还做了一些测试,删除了各种实体属性的验证规则和默认值(基于下面的马库斯的建议)。没有更改,编译器仍然会创建无效的.momd。我还尝试创建一个版本化的模型,没有任何改变:编译后的.momd继续崩溃。因此,无论您在当前模型中拥有什么(以及它们所表示的数据),都是问题的根源。
还要注意的是:这个bug并不是孤立于NSPersistentDocument的(正如我在开始这个问题时所想的那样)。我只需使用[[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]就可以使应用程序崩溃。
现在,我将在雪豹上使用Xcode 4.2编辑/版本我的模型,并将编译的资源移到Lion上的Xcode 4.3.2。如果您以任何方式使用Core数据,我建议您在此bug得到解决之前也这样做。相信我,如果你不这么做,你会花上好几天的时间来弄清楚到底是怎么回事。
现在提交一个雷达…
雷达更新
我刚提交了这个雷达:
http://www.openradar.me/11184500
,噢,废话,那一定是狮子更新
我刚刚从http://developer.apple.com/downloads下载并安装了用于Lion工具的Xcode 4.2。在雷达中使用的示例应用程序仍然崩溃。
(注意:您不能安装Xcode 4.2.1,因为用于签署DeveloperTools.pkg的证书已经过期。只有Xcode 4.2才能工作。)
如果你在NDA之下,你也会发现测试版工具也没有用。
希望你有一份雪豹和Xcode 4.2坐在一起:http://furbo.org/2012/03/28/vmware-for-developers/
WTF提取请求与版本化实体和属性更新有关
在Twitter上通过Evadne Wu:
https://twitter.com/#!/evadne/status/187625192342818818
她是如何做到的:
https://twitter.com/#!/evadne/status/187629091518816258
(.mom文件是二进制plist。)
问题的根源是单个获取请求。这是如何将数据从一种模式转移到另一种模式的,由苹果公司的一位工程师来弄清楚。
发布于 2012-04-04 23:48:31
在将"existingPartner“提取请求从以下位置更改后,可以加载编译的existingPartner资源:
name == $name至:
name == $NAME不影响数据持久性的对象模型的一部分破坏了版本控制和轻量级迁移,这是违反直觉的。从文档中可以明显看出,情况不应该是这样的:
核心数据在版本控制方面的观点是,它只对影响持久性的模型特性感兴趣。
使用乔克洛克的功能来修复您的获取请求或完全删除它们,并依赖于用代码创建的NSPredicates。
发布于 2012-04-03 20:50:22
我认为您需要将托管对象模型存储在实例变量中。您正在返回一个自动释放的对象,这可能是导致错误访问的原因。
发布于 2012-04-04 04:13:24
基于您认为MOMC存在问题的理论,您在MOMC中是否有任何验证规则?
我已经看到了一些报告,其中的验证规则不能生存4.xMOMC。
https://stackoverflow.com/questions/10001026
复制相似问题