【问题标题】:How to use Core Data's ManagedObjectModel inside a framework?如何在框架内使用 Core Data 的 ManagedObjectModel?
【发布时间】:2014-09-25 03:18:00
【问题描述】:

我正在尝试将我的一个应用程序的特定部分迁移到一个框架中,以便我可以在我的应用程序本身和其中一个新奇的 iOS 8 小部件中使用它。这部分是处理我在 Core Data 中的所有数据的部分。将所有内容移动并访问它非常简单。我只是无法访问其中的momd 文件。

创建NSManagedObjectModel 时,我仍然尝试加载momd,如Apple 的代码模板所示:

NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"MyApp" withExtension:@"momd"];
__managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];

不幸的是,modelURL 保持 nil,因此MyApp 在访问核心数据堆栈时崩溃并出现此错误:

2014-08-01 22:39:56.885 MyApp[81375:7417914] Cannot create an NSPersistentStoreCoordinator with a nil model
2014-08-01 22:39:56.903 MyApp[81375:7417914] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Cannot create an NSPersistentStoreCoordinator with a nil model'

那么,在使用 Core Data 的框架内工作时,正确的方法是什么?

【问题讨论】:

  • 文件本身是否包含在您正在构建的目标中?在我看来,您引用的文件没有作为目标构建的一部分添加。
  • 我的 MyApp.xcdatamodeld 包含在我的框架目标的成员资格中,是的。对于momd 文件本身,我不知道是否可以在任何地方进行更改。那不是根据我的xcdatamodeld 文件在构建期间/动态创建的吗?
  • 我从来没有将模型文件作为框架的一部分。当我需要包含模型时,我会从源代码构建模型。但是,我想您的问题是您正在查看主捆绑包。您是否尝试过遍历所有捆绑包,尝试从每个捆绑包中加载模型直到成功?使用[NSBundle allBundles]
  • 是的,我试过了。那对我不起作用。我遍历了所有捆绑包,试图找到“全部”MyApp.momd。在运行完所有捆绑包后,我将存储所有 URL 的数组为空。
  • @flohei 这听起来不对。但是,还有另一种选择,而不是打包您的实际模型文件。设置好模型后,加载它,将其存档到 NSData 对象,然后将其转换为 base64 编码字符串。您可以编写一个简单的程序来执行此操作,或者将其记录到控制台并剪切/粘贴字符串。然后,您可以将变量设置为该 base64 编码字符串。当您的代码运行时,您可以将字符串解码为NSData,然后将其解压缩为NSManagedObjectModel 实例。您的模型现在是已编译库的一部分。

标签: ios core-data frameworks nsbundle nsmanagedobjectmodel


【解决方案1】:

我假设您只需要数据模型。

如果是这样,我发现以下方法始终是将数据模型文件从一个项目复制到另一个项目的最成功方法...

  1. 删除驻留在目标项目中的.xcdatamodeld 文件的所有当前副本。

  2. 关闭 Xcode。

    使用 Finder(或 cmd 行);

  3. 选择包含原始 .xcdatamodeld 文件的 Xcode 项目文件夹。

  4. 复制原始.xcdatamodeld 文件。

  5. 将原始.xcdatamodeld 文件的副本移动到您的目标项目。

    那么……

  6. 打开 Xcode。

  7. 使用菜单命令“将文件添加到>您的项目.xcdatamodeld 文件的副本并将其添加到您的项目中。

  8. 使用 Project Navigator 重命名原始 .xcdatamodeld 文件(如有必要)。

  9. “构建并运行”您的目标项目。

这有帮助吗?

【讨论】:

  • 不,不幸的是这没有帮助。无论如何,我认为移动文件效果很好。只是在运行时无法构造路径,因为(我假设)momd 仍然驻留在原始包(或任何地方)内,并且无法从框架内访问。但这只是一个疯狂的猜测。
【解决方案2】:

我回答这个问题可能有点晚了,但这就是解决我的问题的方法:

通过我的框架,我还提供了一个包含图像和其他东西等资源的捆绑包。将 xcdatamodeld 文件放在那里并没有提供任何东西,因为该文件是与项目一起构建的,因此您在应用程序包中获得了一个 momd 文件夹(实际上在我们的案例).. 我创建了另一个目标,而不是框架,而是应用程序,构建了它并将 momd 从其应用程序包复制到项目中我的单独包(与框架一起使用的包)。 完成此操作后,您只需将资源 url 从主包更改为新的:

// ...
NSString *bundlePath = [[NSBundle mainBundle] pathForResource:@"separate_bundle" ofType:@"bundle"];
NSURL *modelURL = [[NSBundle bundleWithPath:bundlePath] URLForResource:@"your_model" withExtension:@"momd"];
// ...

对我来说工作得很好。我唯一知道的是App Store Review,我还没有接触到。 因此,如果您找到了更好的解决方案,请分享。

编辑

找到更好的解决方案。您可以自己构建模型。来自Core Data Programming Guide

数据模型是一种部署资源。除了细节 模型中的实体和属性,您在 Xcode 中创建的模型 包含有关图表的信息——它的布局、元素的颜色、 等等。运行时不需要后面的信息。该模型 文件是使用模型编译器 momc 编译的,以删除 无关信息并使资源的运行时加载为 尽可能高效。编译 xcdatamodeld “源”目录 进入 momd 部署目录,xcdatamodel “源”文件是 编译成 mom 部署文件。

momc 位于 /Developer/usr/bin/。如果你想在你的 自己的构建脚本,它的用法是momc source destination,其中source 是要编译的核心数据模型的路径,目标是 输出路径。

“/Developer/usr/bin/”的意思是“/Applications/Xcode.app/Developer/usr/bin/

您可以在目标方案中添加一个脚本,并在每次构建之前自动编译它(或之后,不要认为这很重要)。以防您在开发过程中更改模型。

类似这样的:

mkdir -p "${BUILT_PRODUCTS_DIR}/your_model_name.momd"
momc "${SRCROOT}/your_model_path/your_model_name.xcdatamodeld" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework/your_bundle_name.bundle/your_model_name.momd"

【讨论】:

  • 我使用了你上面提到的脚本,但仍然无法访问框架中的核心数据模型,为什么?
  • @dee,请仔细检查我使用的条件名称(如 your_modelyour_model_nameseparate_bundle,等)粘贴代码后。也许您错过了更改其中一个名称特定于您的项目的名称?我在我的项目中积极使用此代码,它对我来说很好用。让我知道您有任何问题。
  • 我确实更改了条件名称。但我发现mkdir -p "${BUILT_PRODUCTS_DIR}/your_model_name.momd" 在构建框架时会导致错误。我必须将其更改为momc "${SRCROOT}/RichAPM/Source/DB/RichAPM.xcdatamodeld" "${BUILT_PRODUCTS_DIR}/your_framework_name.framework/your_bundle_name.bundle/model_name.momd" 即使我构建了框架并成功捆绑,我仍然无法使用模型。请帮我一把好吗?
  • 我终于搞定了,但我必须单独导入框架和捆绑包。
  • @dee,您需要在目标的构建阶段添加我在运行脚本部分发布的脚本。
【解决方案3】:

您需要将 xcdatamodeld 文件拖放到 Build Phases |为使用框架的目标编译源。然后当目标运行时,它的 [NSBundle mainBundle] 将包含模型(momd 文件)。

【讨论】:

  • 那是解决方案,+1
【解决方案4】:

模型资源不再通过mainBundle 访问,您需要像这样使用bundleForClass:

NSURL *modelURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"MyApp" withExtension:@"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];

【讨论】:

  • 感谢您的解决方案!它对我有用,而且很棒!
【解决方案5】:

@Ric Santos 快到了。我认为您只需要将其设为“mom”扩展而不是“momd”,它就会运行。

lazy var managedObjectModel: NSManagedObjectModel = {
    let modelURL = NSBundle(forClass: self.dynamicType.self).URLForResource(self.dataModelName, withExtension: "mom")!
    return NSManagedObjectModel(contentsOfURL: modelURL)!
}()

【讨论】:

  • 遇到了同样的问题,您的解决方案有效!非常感谢!
  • 从 NSBundle.mainBundle() 更改为 NSBundle(forClass: self.dynamicType.self) 对我有用。不过不需要改成“妈妈”。为什么使用 dynamicType 以及为什么没有它就不能工作? :)
【解决方案6】:

我对 flohei 的问题有点晚了,但希望这可以帮助其他路过的人。无需执行 script-fu 复制资源就可以让它工作!

默认情况下,Apple 的核心数据模板为您提供如下内容:

lazy var managedObjectModel: NSManagedObjectModel = {
  let modelURL = NSBundle.mainBundle().URLForResource("MyCoreDataModel", withExtension: "momd")!
  return NSManagedObjectModel(contentsOfURL: modelURL)!
}()

这会将您的核心数据资源从主包中加载出来。这里的关键是:如果 Core Data 模型加载到框架中,.momd 文件在该框架的包中。所以我们只是这样做:

lazy var managedObjectModel: NSManagedObjectModel = {
    let frameworkBundleIdentifier = "com.myorg.myframework"
    let customKitBundle = NSBundle(identifier: frameworkBundleIdentifier)!
    let modelURL = customKitBundle.URLForResource("MyCoreDataModel", withExtension: "momd")!
    return NSManagedObjectModel(contentsOfURL: modelURL)!
}()

这应该可以让您启动并运行。

信用:https://www.andrewcbancroft.com/2015/08/25/sharing-a-core-data-model-with-a-swift-framework/

【讨论】:

  • 这绝对应该是公认的答案,谢谢@Jonathan Zhan
【解决方案7】:

如果您尝试在框架中包含核心数据,请这样做。

在 YourFramework 中 - 添加新文件/核心数据/数据模型... - 创建所有对象 ....

在创建将使用 YourFramework 的新项目时,请确保核心数据位于

这将在 AppDelegate 中创建所有样板。

在测试项目中 - 添加框架 - 添加框架作为嵌入式框架 - 删除 .xcdatamodeld 文件 - 在 AppDelegate 中:

- (NSManagedObjectModel *)managedObjectModel方法改成:

NSBundle * testBundle = [NSBundle bundleWithIdentifier:@"YourFramework bundle id "];

NSURL *modelURL = [testBundle URLForResource:@"Model" withExtension:@"momd"];

其中YourFramework bundle id 是YourFramework 的Bundle Identifier(一般/ Bundle Identifier)

Model 是 YourFramework 中 .xcdatamodeld 文件的名称

这行得通。

希望对你有帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-14
    • 1970-01-01
    • 2011-03-26
    • 2015-07-21
    • 2020-03-10
    • 2014-11-17
    相关资源
    最近更新 更多