ios - RestKit 和 Cocoapods : Mapping operation failed/did not find any mappable values

标签 ios objective-c restkit cocoapods

当使用 RKMappingTest 对 RestKit 映射代码执行单元测试时,它们会失败并出现以下异常:

映射操作失败:给定 nil 目标对象,无法实例化映射的目标对象。

或(当目标对象被传递到 RKMappingTest 时):

映射操作未在给定对象表示中找到属性和关系映射的任何可映射值


RestKit 使用以下 Podfile 通过 Cocoapods 安装:

target :MyTarget do
    pod 'RestKit'
end

target :MyTargetTests do
    pod 'RestKit/Testing'
    pod 'RestKit/Search'
end

要测试的 RKMapping 在常规应用程序包中创建,并在使用 lldb 调试器的 po 命令时正确显示。

当生成 RKEntityMapping 的方法被复制粘贴到单元测试类并在那里执行时,一切正常。


备注:

虽然我确实回答了我自己的问题,希望它对遇到同样问题的其他人有用,但我鼓励任何能提出更好解决方案的人发布它。

最佳答案

发生这种情况的原因:

Disclaimer:
I am no expert on static libraries, linking and related dependencies. If I got something wrong about the way that linking or Cocoapods work, please correct me.

为此Podfile , Cocoapods 构建了两个静态库——每个目标一个。

项目编译时,MyTarget中的所有代码将链接到 LibPods-MyTarget.a库和 MyTargetTests 中的所有代码将链接到 LibPods-MyTargetTests.a图书馆。
它们都包含 RestKit/ObjectMapping 的副本组件(因为它是 RestKitRestKit/Testing 的依赖项)。

生成 RKMapping 时在应用程序源 (MyTarget) 中,来自 LibPods-MyTarget.a 的类实现被使用了。
当在单元测试类中使用该映射时,RestKit 实现从其他库链接。

理论上,两个实现都包含相同的源代码,两个类具有相同的名称、相同的类号,甚至可能是底层 objc_class结构包含相同的内容。

当您从测试类中调用方法时,它将按预期执行(实现来自应用程序库)。 说:根据分配初始化对象的位置,相同的源代码将从不同内存位置的不同副本加载。

但是,由于 Objective-C Class构造比底层更高级别objc_class结构,它们并不相同。


这意味着什么的例子:

假设我们有一个名为 MyObject 的类,其中包括具有以下签名的方法:

+ (RKObjectMapping*)generateMapping;

虽然方法本身工作得很好,但这个测试会失败:

- (void)testClassEquality {
    RKEntityMapping *mappingFromAppBundle = [MyObject generateMapping];
    Class testBundleMappingClass = [RKMapping class];
    
    XCTAssert([mappingFromAppBundle isMemberOfClass:testBundleMappingClass],
              @"Mapping class from app bundle doesn't match Mapping class from test bundle");
}

因为:

[RKMapping class]来自 LibPods-MyTarget.a
!=
[RKMapping class]来自 LibPods-MyTargetTests.a


RestKit 严重依赖 isMemberOfClass:isSubclassOf:实现其功能的操作。因此,这种重复的实现破坏了它。


解决方案:

快速而肮脏:

不要为两个目标使用两种不同的 Cocoapod 配置。使用简单的 Podfile,例如:

pod 'RestKit'    
pod 'RestKit/Testing'
pod 'RestKit/Search'

然后对两个目标使用相同的库/配置。针对两个目标的相同副本的链接器链接。

死代码剥离应该防止不需要的代码包含在您的最终应用程序中。

但是:它仍然需要在每次构建时编译,如果你有 -ObjC-all_load设置了链接器标志,未使用的代码将随您的应用一起发布。

更脏:

I strongly advise against this, since it pretty much defeats the purpose of a unit test. I've seen this as another workaround and included it for the sake of completion:

将代码的实现复制并粘贴到单元测试类中,然后从那里使用它。

建议:

Cocoapods 首先为每个单独的组件创建一个静态库,然后将它们组合成一个更大的库,用于每个目标、项目或工作区。

应该可以在不使用大联合的情况下将小型库直接链接到目标中。通过这样做,在没有自动化的情况下,人们会杀死自动依赖管理,而 Cocoapods 正是为此而构建的。

如果有人有空并为此实现脚本或修改 Cocoapods 以添加功能,请告诉我。


其他解决方案?

如果我遗漏了 Cocoapods 已有的功能,或者您知道任何其他解决方案,请发表评论或将其发布为另一个答案。

关于ios - RestKit 和 Cocoapods : Mapping operation failed/did not find any mappable values,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23860482/

相关文章:

objective-c - 项目中所有 IBOutlet、IBAction 连接的总结?

ios - 执行选择器警告

iphone - 在 UIImageView 中旋转图像

ios - 如何在 IOS 9 的 UIAlertController 中添加按钮

ios - 带有 RestKit v0.21.0 的 XCode 5 项目无法编译

ios - 如何向下转换可以是多种类型的对象?

ios - NSPredicate ANY 多列

ios 所有 UIButton 的全局触觉反馈

ios - RestKit 添加属性映射和关系映射

ios - 未知类型名称 'AFNetworkReachabilityStatus',RestKit 突然停止工作