objective c - 轻量级迁移NSPersistentDocument

Translate

我正在尝试对Core Data中的SQLite存储进行轻量级迁移。使用Xcode 4.3.1在Lion 10.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;
}

(感谢Jeff LaMarche的想法:http://iphonedevelopment.blogspot.com/2009/09/core-data-migration-problems.html)

捆绑软件和URL都指向我期望的位置(并且我遵循Marcus Zarra的建议来清理项目,因此应用程序包中没有任何杂散的.mom或.momd捆绑软件:使用mergedModelFromBundles:和版本控制(CoreData))。但是,从url加载模型时,应用程序仍然崩溃。

我检查了AccountDocument2.xcdatamodeld是一个具有两个版本控制模型的程序包:AccountDocument 2.xcdatamodel和(原始)AccountDocument.xcdatamodel。文件属性中的“ Versioned Core Data Model”弹出菜单设置为“ AccountDocument 2”。

两种模型之间的唯一区别是,一个实体具有附加的(和可选的)属性。我的理解是使模型有资格进行轻量级迁移。

显然,我在这里做错了,但我不知道该怎么办。非常感激任何的帮助…

更新:

根据马丁的建议(以及对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,但问题仍然存在。

愤怒更新

我刚刚在Snow Leopard上使用Xcode 4.2创建了版本控制模型包(AccountDocument2.xcdatamodeld)。构建并运行该应用程序后,一切都会按预期进行。

然后,我将AccountDocument2.xcdatamodeld文件包带回Lion和Xcode 4.3.2。当我构建并运行该应用程序时,加载.momd资源时,它继续崩溃。是的,这是Xcode 4.3.x和数据模型编译器(MOMC)的罪魁祸首。除了在Snow Leopard上完成所有构建工作外,我没有其他解决方法。

我不是要抨击Xcode 4的人,但是当我们发现工具链无法根据不透明的规范(.xcdatamodel和.xcdatamodeld)生成不透明文件(.mom和.momd)时,很难对Mac和iOS工具的状态保持乐观。荒谬的是,这些平台的核心组件破坏到我无法在最新版本的SDK和开发者工具上构建和运行我的应用程序的程度。

这是此更新

进一步证明这是Xcode 4.3.2中数据模型编译器(MOMC)的严重错误:如果我将.momd包从Xcode 4.2创建的Resource文件夹复制到我的项目中,然后将它们作为复制文件添加到内部版本中构建阶段,应用程序运行良好。

我还进行了一些测试,其中删除了各种实体的属性的验证规则和默认值(基于下面的Marcus的建议。)不变,编译器仍然创建了无效的.momd。我还尝试创建一个版本模型,其中未进行任何更改:已编译的.momd继续崩溃。因此,当前模型中的任何内容(及其表示的数据)都是问题的根源。

还要注意:此错误不是孤立于NSPersistentDocument的(就像我最初问这个问题时最初想的那样。)我可以通过仅使用来导致应用程序崩溃[[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL].

现在,我将在Snow Leopard上使用Xcode 4.2编辑/版本化模型,并将编译的资源移至Lion上的Xcode 4.3.2。如果您以任何方式使用Core Data,建议您执行相同的操作,直到解决此错误为止。相信我,如果您不这样做,您将花费数天的时间来弄清楚到底是怎么回事。

现在提交雷达…

雷达更新

我刚刚提交了此Radar:

http://www.openradar.me/11184500

哦废话一定是狮子更新

我刚刚从下载并安装了Lion的Xcode 4.2工具http://developer.apple.com/downloads。 Radar中使用的示例应用程序仍然崩溃。

(注意:您不能安装Xcode 4.2.1,因为用于签署DeveloperTools.pkg的证书已经过期。只有Xcode 4.2可以使用。)

如果您使用的是NDA,您还会发现Beta版工具也无济于事。

希望您能随身带着Xcode 4.2的Snow Leopard副本:http://furbo.org/2012/03/28/vmware-for-developers/

WTF执行获取请求与版本化的实体和属性更新有关

在推特上通过Evadne Wu:

https://twitter.com/#!/evadne/status/187625192342818818

以及她是如何做到的:

https://twitter.com/#!/evadne/status/187629091518816258

(.mom文件是二进制文件。)

问题的根源是单个提取请求。这是如何将数据从一种模型迁移到另一种模型的,这是Apple的工程师要弄清楚的。

This question and all comments follow the "Attribution Required."

所有的回答

Translate

在将“ existingPartner”获取请求从以下位置更改后,可以加载已编译的.momd资源:

name == $name

至:

name == $NAME

违反直觉的是,对象模型的一部分不影响数据的持久性会破坏版本控制和轻量级迁移。从文档中可以明显看出情况并非如此:

Core Data对版本控制的观点是,它仅对影响持久性的模型功能感兴趣。

使用的力量锁定修复您的提取请求或将其完全删除并依靠用代码创建的NSPredicates.

来源
Translate

我认为您需要将托管对象模型存储在实例变量中。您正在返回一个自动释放的对象,这可能是导致访问错误的原因。

来源
Translate

根据您的理论,这是MOMC的问题,您妈妈中是否有任何验证规则?

我看到过一些报告,其中验证规则无法在4.x MOMC中生存。

来源
Z S
Translate

这可能与我在iOS5首次发布Beta5时使用提取请求时遇到的问题有关。这会导致生成警告,并会在启动时使应用程序崩溃。我并不是真正使用fetch请求,所以我将其删除,一切正常:核心数据警告:“版本哈希信息不适用于所有模型”

来源
Leave a Reply
You must be logged in to post a answer.
关于作者