46

我正在尝试对 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;
}

(感谢 Malcolm Crawford 的提示: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 捆绑包:使用 mergeModelFromBundles:和版本控制(CoreData))。然而,应用程序在从 url 加载模型时继续崩溃。

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

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

显然,我在这里做错了什么,但我不知道是什么。任何帮助将不胜感激……</p>

更新:

根据 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;
}

还在崩溃……</p>

更新

在 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) 的一个严重错误:如果我将 Xcode 4.2 创建的 Resource 文件夹中的 .momd 包复制到我的项目中,并将它们作为复制文件添加到构建中构建阶段,应用程序工作正常。

我还做了一些测试,删除了各种实体的属性的验证规则和默认值(基于下面 Marcus 的建议。)没有变化,编译器仍然会创建一个无效的 .momd。我还尝试创建一个没有任何更改的版本化模型:编译后的 .momd 继续崩溃。因此,无论您在当前模型中拥有什么(以及它们所代表的数据)都是问题的根源。

另请注意:此错误并非孤立于 NSPersistentDocument (正如我在开始此问题时最初所想的那样。)我可以通过使用[[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL].

现在,我将在 Snow Leopard 上使用 Xcode 4.2 编辑/版本控制我的模型,并将编译后的资源转移到 Lion 上的 Xcode 4.3.2。如果您以任何方式使用 Core Data,我建议您在解决此错误之前也这样做。相信我,如果你不这样做,你会花几天时间弄清楚到底发生了什么。

现在提交雷达…</p>

雷达更新

我刚刚提交了这个雷达:

http://www.openradar.me/11184500

哦,废话,它一定是狮子更新

我刚刚从http://developer.apple.com/downloads下载并安装了 Xcode 4.2 for Lion 工具。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 在 Twitter 上:

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

以及她是如何做到的:

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

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

问题的根源在于单个 Fetch Request。这如何影响数据从一个模型到另一个模型的迁移需要 Apple 的一位工程师来弄清楚。

4

4 回答 4

11

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

name == $name

至:

name == $NAME

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

Core Data 对版本控制的看法是,它只对影响持久性的模型特性感兴趣。

使用CHOCKLOCK的强大功能来修复您的 Fetch Requests 或完全删除它们并依赖在代码中创建的 NSPredicates

于 2012-04-04T23:48:31.860 回答
1

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

于 2012-04-03T20:50:22.410 回答
1

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

我已经看到了验证规则在 4.x MOMC 中不存在的报告。

于 2012-04-04T04:13:24.860 回答
0

这可能与我在 iOS5 首次推出测试版时使用 Fetch Requests 时遇到的问题有关。它会导致构建警告,并会在启动时使应用程序崩溃。我并没有真正使用获取请求,所以我删除了它并且一切正常: 核心数据警告:“版本哈希信息不适用于所有模型”

于 2012-04-05T08:14:39.387 回答