35

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

创建时,NSManagedObjectModel我仍然尝试加载momdApple 的代码模板中所示的内容:

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

不幸的是,在访问modelURLCore Data 堆栈时会出现以下错误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 的框架内工作时,正确的方法是什么?

4

7 回答 7

40

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

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

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

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

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/

于 2015-11-01T08:42:27.267 回答
13

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

于 2015-04-05T01:14:35.223 回答
7

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

lazy var managedObjectModel: NSManagedObjectModel = {
    let modelURL = NSBundle(forClass: self.dynamicType.self).URLForResource(self.dataModelName, withExtension: "mom")!
    return NSManagedObjectModel(contentsOfURL: modelURL)!
}()
于 2015-08-09T08:05:01.650 回答
4

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

通过我的框架,我还提供了一个包含图像和其他东西等资源的捆绑包。将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,我还没有接触到。因此,如果您找到了更好的解决方案,请分享。

编辑

找到了更好的解决方案。您可以自己构建模型。来自核心数据编程指南

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

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

“/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"
于 2014-11-27T15:36:44.363 回答
2

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

NSURL *modelURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"MyApp" withExtension:@"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
于 2015-06-30T04:17:01.053 回答
0

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

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

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

  2. 关闭 Xcode。

    使用 Finder(或 cmd 行);

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

  4. .xcdatamodeld制作原始文件的副本。

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

    然后...

  6. 打开 Xcode。

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

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

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

这有帮助吗?

于 2014-08-02T03:02:13.113 回答
0

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

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

创建将使用 YourFramework 的新项目时,请确保核心数据已打开使用核心数据:开启

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

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

- (NSManagedObjectModel *)managedObjectModel方法更改为:

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

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

YourFrameworkYourFramework bundle id的Bundle Identifier在哪里(一般/ Bundle Identifier)

并且Model是 YourFramework 中 .xcdatamodeld 文件的名称

这行得通。

希望能帮助到你。

于 2015-11-08T20:36:20.347 回答