核心数据在iPhone的静态库中
我已经构build了大量使用Core Data框架的静态库。 我可以成功地在我的外部项目中使用库,但只有在主项目中包含.xcdatamodel文件。 这并不理想,因为图书馆的目的是尽可能隐藏实施细节。
在另外一个问题中 ,我被告知,我不能将资源与一个图书馆捆绑在一起(这对我来说是完全有意义的)。
那么是否有一种方法可以在不需要将模型包含在主项目中的情况下以编程方式让模型“被发现”?
我也创build了自己的使用核心数据的静态库。 除了静态库之外,我在项目中还有一个bundle目标,在这个目录中有一个Copy Bundle Resources项目,它将一些图像和类似的东西复制到bundle中,在编译源代码的阶段编译xcdatamodel。
最终的包将包含所有必要的文件。 在依赖静态库的主项目中,还必须包含该包。 您的主项目现在可以访问使用核心数据所需的mom文件。
要从包中使用核心数据,必须在代码中创build一个合并的托pipe对象模型(可能主项目也有一些核心数据模型):
- (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,只有编译的妈妈文件需要包括在内。
Sascha的回答让我走上了正轨。 将一个静态库中的编译后的.mom
文件合并到一个主机项目的.mom
文件中是比较简单的。 这是一个简单的例子:
-
创build一个名为
MyStaticLibrary
的新的XCode静态库项目 -
在
MyStaticLibrary
创build一个名为MyStaticLibraryModels.xcdatamodel
的.xcdatamodel文件,添加一些Entity
,然后生成头文件和实现。 当您构buildMyStaticLibrary
目标时,您将生成一个libMyStaticLibrary.a
二进制文件,但不包括已编译的.mom
文件。 为此,我们必须创build一个包。 -
创build一个types为
Loadable Bundle
的新构build目标,在MacOS X > Cocoa
下find,让我们调用新的TargetMyStaticLibraryModels
。 -
将
MyStaticLibraryModels.xcdatamodel
拖动到MyStaticLibraryModels
目标的Compile Sources
构build阶段。 构buildMyStaticLibraryModels
目标时,将生成一个名为MyStaticLibraryModels.bundle
的文件,它将包含已编译的NSManagedObjectModel
文件MyStaticLibraryModels.mom
。 -
在构build
MyStaticLibrary
和MyStaticLibraryModels
目标之后,将libMyStaticLibrary.a
(以及任何关联的Model头文件)和MyStaticLibraryModels.bundle
到您的主机项目MyAwesomeApp
。 -
MyAwesomeApp
使用CoreData
,它有自己的.xcdatamodel
文件,它将在自己的构build过程中被编译成一个.mom文件。 我们要将这个.mom
文件与我们在MyStaticLibraryModels.bundle
导入的文件合并。 在MyAwesomeApp
项目的某个地方,有一个方法返回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_; }
这将从MyAwesomeApp
和MyStaticLibrary
返回合并的NSManagedObjectModel
与Entity
。
不,在iPhone应用程序中使用非Apple框架的限制实际上改变了与OS X相关的依赖性游戏。大多数iPhone“框架”(例如Google的Mac,Core Plot等工具箱)实际上build议您将源代码包含在你的主应用程序项目,而不是链接一个产品(即静态库)。 我认为社区的共识是,在iPhone上,期望你的框架的消费者不得不做一些“手动”的工作来使用你的库。 在你的情况下,这是在主项目中包括xcdatamodel文件。 与Objective-C的大部分一样,告诉用户不要使用实现细节并保留。
我也有一些Coredata的图书馆。 我发现这个模板用于pipe理embedded资源的框架
在一个新的项目上使用起来非常简单(对现有的应用来说更加困难),但是对于框架构build来说,这真的很酷:-)
Sascha Konietzke的解决scheme运作良好,但有一个重要的警告,需要提供它的工作。 包含模型的bundle需要先被加载,否则不会被包含在数组中并合并到MOM中。
在他的情况下,他可能已经从bundle中访问了资源,因此在这个代码被执行之前,bundle已经被加载了。
Prairiedogg的答案有点过时了,下面是在Xcode 5中这样做的教程: http : //bharathnagarajrao.wordpress.com/2014/02/14/working-with-core-data-in-a-static-library/
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! }()
请注意,不是使用xcdatamodel / mom文件,您也可以在代码中创build模型(特别是如果您有一个简单的模型),这样就不需要为资源创build额外的包。 下面是一个包含两个属性的表格的简单示例:
- (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; }
这是一个关于从代码创build模型的教程: https : //www.cocoanetics.com/2012/04/creating-a-coredata-model-in-code/
同样基于这种方法,我创build了一个小巧易用的库,可能适合您的需求,称为LSMiniDB,所以你也可以检查它。
- NSFetchedResultsController与UILocalizedIndexedCollation
- 如何asynchronous同步CoreData和REST Web服务,同时正确地将任何REST错误传播到UI中
- Xcode 4,核心数据模型版本 – 设置当前版本
- 核心数据-existingObjectWithID:错误:导致错误133000
- NSManagedObjectContext performBlockAndWait:不在后台线程上执行?
- JSON和核心数据在iPhone上
- 如何查看存储在Core Data中的数据?
- 好的核心数据教程?
- 在iPhone上为Core Data程序创build一个唯一的ID