当模型放置在静态库中时,executeFetchRequest 返回类型发生了变化

Posted

技术标签:

【中文标题】当模型放置在静态库中时,executeFetchRequest 返回类型发生了变化【英文标题】:executeFetchRequest return type changed when model placed in static library 【发布时间】:2011-02-13 16:39:56 【问题描述】:

我希望这对于比我有更多 Core Data 和 XCode 经验的人来说是一件容易的事。

我正在尝试将 ios 应用程序的模型层移动到静态库,以便我可以重用它。我已成功分离代码并构建/运行应用程序。不幸的是,我遇到了一个特殊的问题。

考虑以下代码sn-p:

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];

NSEntityDescription *entityDescription = [NSEntityDescription entityForName:entityName inManagedObjectContext:context];
[fetchRequest setEntity:entityDescription];
fetchRequest.includesSubentities = NO;
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"UID = %@", uID]];
fetchArray = [context executeFetchRequest:fetchRequest error:&fetchError];
id obj = [fetchArray objectAtIndex:0];
NSString *fetchArrayIndexZeroEntityName = [[obj entity] name];

当一切都在一个 xcode 项目中时: 根据 xcode 调试器悬停气泡的 obj 指针类型是 MyCustomCoreDataClassName

fetchArrayIndexZeroEntityName = @"MyCustomCoreDataClassName"

将核心数据模型移动到静态库后: 根据 xcode 调试器悬停气泡的 obj 指针类型是 NSManagedObject

fetchArrayIndexZeroEntityName = @"MyCustomCoreDataClassName"

稍后在我的代码中我进行以下调用:

[obj isKindOfClass:[MyCustomCoreDataClassName class]]

当所有内容都在单个 xcode 项目中时,上述调用返回 YES。 在我将核心数据模型移动到静态库后,上述调用返回 NO。

这种行为显然对我的应用程序产生了相当可怕的后果。对可能出现的问题以及如何解决问题有任何想法吗?完全有可能我将这些项目不完整或不正确地链接在一起,即使它编译时没有错误并且运行至少足以发现上述内容。

谢谢你, 安德鲁

【问题讨论】:

【参考方案1】:

根据您设置核心数据堆栈的方式,就在它的内部,检查当您读取通常从 NSBundle 实例化的 NSManagedObjectModel(s) 时,您是否有一些有效的实体。在模型返回的项目中设置断点,然后在调试器调用中:

po [[managedObjectModel entitiesByName] allKeys]

如果返回实体列表,那么我不确定到底发生了什么,但是,我怀疑它会返回一个空列表,因为代码在您的项目中找不到任何 mom 文件。

这是我为解决这个问题所做的。在您的静态库项目中(或者如果您的静态库只是主项目中的另一个目标),创建一个新的 NSBundle 目标。将 Core Data 模型和您拥有的任何映射模型添加到此目标。然后将其作为依赖项添加到您的静态库目标和应用程序目标。在您的主应用程序目标中,将此新包添加到 Copy Bundle Resources 构建阶段。

然后,在您的 Core Data 堆栈中,您只需在所有捆绑包中搜索模型。我的代码有点像这样:

/**
 Creates, retains, and returns the managed object model for the application 
 by merging all of the models found in the application bundle.
 */

- (NSManagedObjectModel *)managedObjectModel 

    if (managedObjectModel) return managedObjectModel;

    // Get all the bundles including ones nested inside the main bundle
    NSMutableSet *allBundles = [NSMutableSet set];
    NSMutableSet *newBundles = [NSMutableSet set];
    NSUInteger numberOfBundles = 0;
    [allBundles addObject:[NSBundle mainBundle]];

    while (numberOfBundles < [allBundles count]) 
        // Look for nested bundles
        for(NSBundle *bundle in allBundles) 
            NSArray *morePaths = [NSBundle pathsForResourcesOfType:@".bundle" inDirectory:[bundle bundlePath]];
            if([morePaths count] > 0) 
                for(NSString *bundlePath in morePaths) 
                    if(![allBundles containsObject:bundlePath])
                        [newBundles addObject:[NSBundle bundleWithPath:bundlePath]];                    
                
            
        
        // Add the new bundles
        [allBundles unionSet:newBundles];
        numberOfBundles = [allBundles count];
    

    managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:[allBundles allObjects]] retain];

    if (managedObjectModel) return managedObjectModel;  

    return nil;

请注意,上面的代码不需要知道您为模型命名的内容。我在一个单例类中有这个函数,它还实例化持久存储协调器并返回 MOC。如此有效,一旦你完成了,你就可以在任何地方使用 Core Data 堆栈了,你可以在应用程序的任何地方实例化它。

如果人们想要的话,我想我可以在某个地方发布它的来源。无论如何,希望这能让你走上正轨。

【讨论】:

另外 - 该函数中没有任何错误检查,所以,显然它还没有准备好应用程序,因为如果 managedObjectModel 加载失败,什么都不会工作。 查看github.com/blindingskies/BSManagedObjectContextController了解如何执行此操作。

以上是关于当模型放置在静态库中时,executeFetchRequest 返回类型发生了变化的主要内容,如果未能解决你的问题,请参考以下文章

如何使用静态库(iOS)在应用程序中隐藏核心数据模型?

当两个成员都在同一个类中时,出现错误“非静态成员引用必须相对于特定对象”

静态库的制作和使用

当一个函数(来自一个库)包含在 VC++ MFC 项目中时,“CoInitialize failed”

当节点不在视图中时如何删除它?

包装在静态函数中时,Alamofire 4.0“调用中的额外参数'方法'”