找不到momd文件:Core Data问题

19

啊噢!我搞砸了些什么!

我是一个Core Data新手,正在开发我的第一个iOS应用程序。在Stack Overflow上找了很多资料后,我使用了这段代码:

NSString *path = [[NSBundle mainBundle] pathForResource:@"CoreData" ofType:@"momd"];
if (!path) {
    path = [[NSBundle mainBundle] pathForResource:@"CoreData" ofType:@"mom"];
}
NSAssert(path != nil, @"Unable to find Resource in main bundle");

CoreData是我的应用程序名称。

我尝试通过找到iPhone模拟器中sqlite文件的路径并插入该sqlite文件来向应用程序添加初始数据。但是在某个时刻,当我移动了这个sqlite文件时(以为它会创建一个新副本),将应用程序从模拟器中删除后,该sqlite文件就不见了。我不确定是否遗漏了一些步骤(这是几小时前的事了),但最终结果是一切都被搞砸了。

我该如何重新实例化这个sqlite/momd文件?“Clean”和“Clean all targets”选项都灰色不可用。

我很乐意发布我应用程序中相关的代码,以帮助解决这个问题,但涉及到Core Data的代码有很多我不理解的部分,所以我不确定应该发布哪一部分!任何帮助都将不胜感激。


对于其他遇到这个问题的人,请注意:在 pathForResource 中给出的 momd 文件夹名称是区分大小写的! - Arsalan Habib
5个回答

45

以下是几个建议:

  • 您发布的获取.mom(d)文件的代码并不是推荐的方法。请使用mergedModelFromBundles,如下所示:

    self.managedObjectContent= [NSManagedObjectModel mergedModelFromBundles:nil];
    

    这个方法会自动完成路径获取、选择/合并正确的mommomd,以及初始化MOC。你应该使用它。不过需要注意的是,有时候需要清理一下构建过程,就像在这个SO问题/答案中讨论的那样。

  • 这表明,虽然搜索 StackOverflow 通常很好,但当处理像 CoreData 这样的大型框架时,这不是最佳方法。

    老实说,花一天时间从头到尾阅读文档。也许你想要谷歌代码片段并立即开始编码,但透彻阅读文档肯定可以在长远来看节省开发时间。

    此外,Marcus Zarra 的 CoreData 书籍(见这里)对我帮助很大。它可能看起来很昂贵,但完全值得。

  • 另一个话题,我认为将预先生成的 sqlite 文件放入模拟器目录(~/Library/Application Support/iPhone Simulator/内)甚至是为了开发的目的也不是一个好策略......因为它无法在实际设备上工作。如果需要这样做,把 sqlite 文件作为应用程序的资源,并在启动时将其复制到DocumentsCaches中,然后再使用。


4
我认为你不应该说它“选择”任何东西,也肯定不会初始化MOC。它所做的就是找到给定包中的所有模型并合并它们。如果您不需要合并多个模型,则指定模型URL也没有什么问题。苹果明确提出了这种解决方案和干净选项,作为CD编程指南中针对此特定问题的解决方案。 - lhunath
1
@lhunath 我一直在研究Core Data,我可以确认Apple确实表示:initWithContentsOfURL: 是通常首选的技术。感谢Yuji提供的链接。可能会去看看这本书。 - pnizzle
如果您的应用程序是由不同团队使用单独的 MOM 构建的,以处理应用程序的不同部分,则肯定不希望将主包中找到的所有模型合并为一个特定上下文的模型!它们会不必要地纠缠在一起。此外,苹果公司的《Core Data 编程指南》在“初始化 Core Data 堆栈”部分显示从 NSBundle URLForResource:withExtension: 传递 NSURL 到 NSManagedObjectModel initWithContentsOfURL:。这可能是 2010 年的一个很好的答案,但在 2015 年可能会误导开发人员。 - Jeff
根据我的经验,有时仅仅清理并不能解决问题,我必须要重新启动Xcode和/或删除~/Library/Developer/Xcode/DerivedData目录下的内容 - Daniel

18

如果清理目标菜单项变成了灰色,可能是应用程序正在运行。

你获取mom/momd路径的方式看起来像是在事后集成CoreData(而不是在创建项目时选择包含它)。我和你遇到的问题一样。默认代码寻找momd时假定它已经存在,如果你将数据模型的一个版本添加到项目中,你也应该能够找到它。

要实现这一点,请选择xcdatamodel文件,在Design菜单中选择Data Model > Add Model Version。然后,你会得到一个带有子树的CoreData.xcdatamodeld,其中包含Coredata.xcdatamodel和一个新版本。你只需删除多余的版本,就可以得到所需的层次结构。如果你进行构建并查看App包,你就会看到CoreData.momd目录中包含mom文件。

这些步骤在我找到的任何CoreData教程中都没有提到。希望会对你有所帮助!


1
这对我有效。事实上,我在添加CoreData之后出现了“nil model”错误,因为我的构建中没有mom(d)。执行“添加模型版本”(+删除重复版本)解决了问题! - RickDT
3
在 Xcode 4 中,您可以通过选择“编辑器”->“添加模型版本”来添加新版本。 - Teetotum
这正是我一直在寻找的其他教程没有提到的缺失部分!谢谢! - keegan3d

7
实用的答案: 如果您遇到路径问题,可以尝试以下代码。您还需要检查您的xcdatamodel文件是否作为目标资源包含在内。
[[NSBundle bundleForClass:[self class]] pathForResource:@"CoreData" ofType:@"momd"]

更好的答案:momd文件表示您的NSManagedObjectModel,而sqlite文件由您的NSPersistentStore对象使用。与CoreData一起工作的最佳方法是让SDK处理与sqlite的所有交互。您唯一需要设置有关sqlite的事情是告诉NSPersistantStore在哪里放置您的sqlite文件。您在托管对象模型中定义的托管对象将为您处理所有数据插入和更新。
如果您不熟悉我引用的对象,请查看苹果文档以获取非常有帮助的概述。您绝对需要花时间了解完整的CoreData堆栈,因为如果按照Apple的期望方式使用Core Data,这个时间投资将在减少头痛的同时得到回报。这比许多Web开发人员习惯的抽象设计更抽象,但尝试通过直接使用SQLite绕过该抽象会创建自己的复杂性。
参考链接:http://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreData/Articles/cdBasics.html#//apple_ref/doc/uid/TP40001650-TP1

这对我有用,我进行了一次合并,由于某种原因,xcdatamodel文件从复制到应用程序的资源列表中被删除了。 - Joel Martinez

4

我发现在模拟器的“磁盘映像”中查看我的可执行文件非常有价值。

如果您进入~/Library/Application Support/iPhone Simulator//Applications,您可以看到手机上的应用程序。找出哪个是你的(使用find或查看日期),然后浏览到你的target.app并寻找.momd文件。

在我的情况下,我的momd名称与我的.xcdatamodeld文件名称不同,这就是为什么core data无法加载它的原因。一旦我在AppDelegate中更正了名称,事情就开始正常工作了。

请注意,momd“文件”似乎实际上是一个目录(就像.app设置)。

--

关于添加初始化core data的代码; 我也做了这件事。我创建了一个启用了core data的新空项目,并复制了AppDelegate文件中所有与core data初始化步骤相关的内容。有很多与初始化整个堆栈相关的东西,所以如果没有出现,您需要将其放在那里。


这解决了我的问题。我从示例中复制+粘贴,并填写了我认为正确的momd文件名。结果发现文件名与我想的不同。+1 - meddlingwithfire

2
如果您已经给您的模型添加了版本信息,请将.mom更改为.momd。
    NSString *path = [[NSBundle mainBundle] pathForResource:@"CoreData" ofType:@"momd"];
if (!path) {
    path = [[NSBundle mainBundle] pathForResource:@"CoreData" ofType:@"momd"];

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接