iPhone静态库中的核心数据

时间:2009-11-10 22:08:31

标签: iphone core-data static-libraries nsbundle

我已经构建了一个大量使用Core Data框架的静态库。我可以在我的外部项目中成功使用该库,但仅限于我在主项目中包含.xcdatamodel文件。这不太理想,因为库的重点是尽可能隐藏实现细节。

在一个单独的question中,我被告知我无法将资源与库捆绑在一起(这对我来说完全合情合理)。

那么有没有办法以编程方式允许模型“被发现”,而不必将模型包含在主项目中?

8 个答案:

答案 0 :(得分:58)

Sascha的回答让我走上正轨。将来自静态库的已编译.mom文件合并到主机项目的.mom文件中相对简单。这是一个简单的例子:

  1. 创建一个新的XCode静态库 项目名为MyStaticLibrary

  2. 在名为MyStaticLibrary的{​​{1}}中创建一个.xcdatamodel文件,添加一些MyStaticLibraryModels.xcdatamodel,然后生成标头和实现。构建Entity目标时,您将生成MyStaticLibrary二进制文件,但不包含已编译的libMyStaticLibrary.a文件。为此,我们必须创建一个包。

  3. .mom下创建Loadable Bundle类型的新构建目标,让我们调用新目标MacOS X > Cocoa

  4. MyStaticLibraryModels拖到MyStaticLibraryModels.xcdatamodel目标的Compile Sources构建阶段。构建MyStaticLibraryModels目标时,您将生成一个名为MyStaticLibraryModels的文件,它将包含已编译的MyStaticLibraryModels.bundle文件NSManagedObjectModel

  5. 在构建MyStaticLibraryModels.momMyStaticLibrary目标之后,将MyStaticLibraryModels(以及任何关联的模型标题文件)和libMyStaticLibrary.a拖到您的主机项目中,{ {1}}。

  6. MyStaticLibraryModels.bundle使用MyAwesomeApp,拥有自己的MyAwesomeApp文件,该文件将在自己的构建过程中编译成.mom文件。我们希望将此CoreData文件与我们在.xcdatamodel中导入的文件合并。在.mom项目的某个位置,有一个返回MyStaticLibraryModels.bundle s MyAwesomeApp的方法。 Apple为此方法生成的模板如下所示:

  7. ...

    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构建,它真的很酷: - )

https://github.com/kstenerud/iOS-Universal-Framework

答案 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!
}()