我已经构建了一个大量使用Core Data框架的静态库。我可以在我的外部项目中成功使用该库,但仅限于我在主项目中包含.xcdatamodel文件。这不太理想,因为库的重点是尽可能隐藏实现细节。
在一个单独的question中,我被告知我无法将资源与库捆绑在一起(这对我来说完全合情合理)。
那么有没有办法以编程方式允许模型“被发现”,而不必将模型包含在主项目中?
答案 0 :(得分:58)
Sascha的回答让我走上正轨。将来自静态库的已编译.mom
文件合并到主机项目的.mom
文件中相对简单。这是一个简单的例子:
创建一个新的XCode静态库
项目名为MyStaticLibrary
在名为MyStaticLibrary
的{{1}}中创建一个.xcdatamodel文件,添加一些MyStaticLibraryModels.xcdatamodel
,然后生成标头和实现。构建Entity
目标时,您将生成MyStaticLibrary
二进制文件,但不包含已编译的libMyStaticLibrary.a
文件。为此,我们必须创建一个包。
在.mom
下创建Loadable Bundle
类型的新构建目标,让我们调用新目标MacOS X > Cocoa
。
将MyStaticLibraryModels
拖到MyStaticLibraryModels.xcdatamodel
目标的Compile Sources
构建阶段。构建MyStaticLibraryModels
目标时,您将生成一个名为MyStaticLibraryModels
的文件,它将包含已编译的MyStaticLibraryModels.bundle
文件NSManagedObjectModel
。
在构建MyStaticLibraryModels.mom
和MyStaticLibrary
目标之后,将MyStaticLibraryModels
(以及任何关联的模型标题文件)和libMyStaticLibrary.a
拖到您的主机项目中,{ {1}}。
MyStaticLibraryModels.bundle
使用MyAwesomeApp
,拥有自己的MyAwesomeApp
文件,该文件将在自己的构建过程中编译成.mom文件。我们希望将此CoreData
文件与我们在.xcdatamodel
中导入的文件合并。在.mom
项目的某个位置,有一个返回MyStaticLibraryModels.bundle
s MyAwesomeApp
的方法。 Apple为此方法生成的模板如下所示:
...
MyAwesomeApp
我们将更改此选项以合并并返回我们的NSManagedObjectModel
,- (NSManagedObjectModel *)managedObjectModel {
if (managedObjectModel_ != nil) {
return managedObjectModel_;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"MyAwesomeApp" withExtension:@"momd"];
managedObjectModel_ = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return managedObjectModel_;
}
和NSManagedObjectModel
的两个,作为单个,合并MyAwesomApp
,如下所示:
MyStaticLibraryModels
这将返回合并的NSManagedObjectModel
与- (NSManagedObjectModel *)managedObjectModel {
if (managedObjectModel_ != nil) {
return managedObjectModel_;
}
NSMutableArray *allManagedObjectModels = [[NSMutableArray alloc] init];
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"MyAwesomeApp" withExtension:@"momd"];
NSManagedObjectModel *projectManagedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
[allManagedObjectModels addObject:projectManagedObjectModel];
[projectManagedObjectModel release];
NSString *staticLibraryBundlePath = [[NSBundle mainBundle] pathForResource:@"MyStaticLibraryModels" ofType:@"bundle"];
NSURL *staticLibraryMOMURL = [[NSBundle bundleWithPath:staticLibraryBundlePath] URLForResource:@"MyStaticLibraryModels" withExtension:@"mom"];
NSManagedObjectModel *staticLibraryMOM = [[NSManagedObjectModel alloc] initWithContentsOfURL:staticLibraryMOMURL];
[allManagedObjectModels addObject:staticLibraryMOM];
[staticLibraryMOM release];
managedObjectModel_ = [NSManagedObjectModel modelByMergingModels:allManagedObjectModels];
[allManagedObjectModels release];
return managedObjectModel_;
}
和NSManagedObjectModel
中的Entity
。
答案 1 :(得分:30)
我还创建了自己的使用Core Data的静态库。除了静态库,我在项目中有另一个bundle目标,我有一个Copy Bundle Resources项,它将一些图像和类似的东西复制到bundle和Compile Sources构建阶段,我正在编译xcdatamodel。
最终的包将包含所有必需的文件。在依赖于静态库的主项目中,您还必须包含该捆绑包。您的主项目现在可以访问使用核心数据所需的mom文件。
要使用捆绑中的妈妈使用核心数据,您必须在代码中创建合并的托管对象模型(可能主要项目也有一些核心数据模型):
- (NSManagedObjectModel *) mergedManagedObjectModel
{
if (!mergedManagedObjectModel)
{
NSMutableSet *allBundles = [[[NSMutableSet alloc] init] autorelease];
[allBundles addObjectsFromArray: [NSBundle allBundles]];
[allBundles addObjectsFromArray: [NSBundle allFrameworks]];
mergedManagedObjectModel = [[NSManagedObjectModel mergedModelFromBundles: [allBundles allObjects]] retain];
}
return mergedManagedObjectModel;
}
只需包含捆绑包就不必提供xcdatamodel,只需要包含已编译的妈妈文件。
答案 2 :(得分:2)
不,在iPhone应用程序中使用非Apple框架的限制确实改变了相对于OS X的依赖性游戏。大多数iPhone“框架”(例如Google的Mac工具箱,Core Plot等)实际上推荐您将源包含在主应用程序项目中,而不是链接产品(即静态库)。我认为社区的共识是,在iPhone上,可以期望您的框架的消费者必须做一些“手动”工作来使用您的库。在您的情况下,这包括主项目中的xcdatamodel文件。与大多数Objective-C一样,请告知您的用户不要使用实现细节,并将其留在那里。
答案 3 :(得分:2)
我也有一些带有coredata的图书馆。 我找到了这个模板来管理嵌入式资源的框架
在新项目中使用非常简单(在现有项目上更难应用) 但是对于framewoks构建,它真的很酷: - )
答案 4 :(得分:2)
Sascha Konietzke的解决方案效果很好,但需要提供一个重要的警告才能使其工作。需要首先加载包含模型的包,否则它将不包含在数组中并合并到MOM中。
在他的情况下,他可能已经从bundle中访问了资源,因此在执行此代码之前已经加载了bundle。
答案 5 :(得分:2)
Prairiedogg的回答有点过时了,这是关于在Xcode 5中执行此操作的教程:http://bharathnagarajrao.wordpress.com/2014/02/14/working-with-core-data-in-a-static-library/
答案 6 :(得分:1)
请注意,除了使用xcdatamodel / mom文件,您还可以在代码中创建模型(特别是如果您有一个简单的模型),这样您就不需要为资源创建额外的包。这是一个简单的示例,其中一个表包含两个属性:
- (NSManagedObjectModel *)coreDataModel
{
NSManagedObjectModel *model = [NSManagedObjectModel new];
NSEntityDescription *eventEntity = [NSEntityDescription new];
eventEntity.name = @"EventEntity";
eventEntity.managedObjectClassName = @"EventEntity";
NSAttributeDescription *dateAttribute = [NSAttributeDescription new];
dateAttribute.name = @"date";
dateAttribute.attributeType = NSDateAttributeType;
dateAttribute.optional = NO;
NSAttributeDescription *typeAttribute = [NSAttributeDescription new];
typeAttribute.name = @"type";
typeAttribute.attributeType = NSStringAttributeType;
typeAttribute.optional = NO;
eventEntity.properties = @[dateAttribute, typeAttribute];
model.entities = @[eventEntity];
return model;
}
以下是从代码创建模型的教程:https://www.cocoanetics.com/2012/04/creating-a-coredata-model-in-code/
同样基于这种方法,我创建了一个小巧且易于使用的库,可以满足您的需求LSMiniDB,因此您也可以检查它。
答案 7 :(得分:0)
Swift 2版本为Sascha的回答:
lazy var managedObjectModel: NSManagedObjectModel = {
// The managed object model for the application. This property is not optional. It is a fatal error for the application not to be able to find and load its model.
var allBundles = NSMutableSet()
allBundles.addObjectsFromArray(NSBundle.allBundles())
allBundles.addObjectsFromArray(NSBundle.allFrameworks())
let model = NSManagedObjectModel.mergedModelFromBundles(allBundles.allObjects as? [NSBundle])
return model!
}()