RestKit & Cocoapods:映射操作失败/没有找到任何可映射的值

Posted

技术标签:

【中文标题】RestKit & Cocoapods:映射操作失败/没有找到任何可映射的值【英文标题】:RestKit & Cocoapods: Mapping operation failed / did not find any mappable values 【发布时间】:2014-05-25 22:17:21 【问题描述】:

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

Mapping operation failed: Given nil destination object and unable to instantiate a destination object for mapping.

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

Mapping operation did not find any mappable values for the attribute and relationship mappings in the given object representation


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

target :MyTarget do
    pod 'RestKit'
end

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

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

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


注意:

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

【问题讨论】:

【参考方案1】:

发生这种情况的原因:

免责声明:我不是静态库、链接和相关依赖项方面的专家。如果我对链接或 Cocoapods 的工作方式有任何错误,请纠正我。

对于这个Podfile,Cocoapods 构建了两个静态库——每个目标一个。

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

在应用程序源(MyTarget)中生成RKMapping 时,使用来自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'

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

dead-code-stripping 应该防止不需要的代码包含在您的最终应用程序中。

但是:仍然需要在每次构建时对其进行编译,如果您设置了 -ObjC-all_load 链接器标志,则未使用的代码将随您的应用一起提供。

更脏:

我强烈建议不要这样做,因为它几乎违背了单元测试的目的。我将其视为另一种解决方法,并将其包括在内以完成:

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

建议:

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

应该可以将小型库直接链接到目标而不使用大联合。这样做,如果没有自动化,就会破坏自动依赖管理,而 Cocoapods 就是为之而构建的。

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


其他解决方案?

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

【讨论】:

我遇到了同样的问题,但是当我尝试快速而肮脏的解决方案时,我在 RK 类上收到重复的警告。有什么建议吗? 你找到解决办法了吗? @Tim Bodeit,你是如何继续使用相同的配置的? 通常由pod install自动设置。但要确保:在配置下的信息选项卡中转到您的项目设置 -> 基于配置文件。

以上是关于RestKit & Cocoapods:映射操作失败/没有找到任何可映射的值的主要内容,如果未能解决你的问题,请参考以下文章

没有带有 cocoapods 和 swift 的模块“RestKit”

错误:“沙箱与 Podfile.lock 不同步...”在使用 cocoapods 安装 RestKit 后

通过 Cocoapods 安装 RestKit 0.20.0 后基础类型未知

Restkit 0.20.x cocoapods 安装问题 - 编译但找不到 RestKit 的导入

通过 CocoaPods 在 github 上使用 Restkit 的一个分支?

iOS7 是不是有轻量级 JSON 到对象映射器(不是 RestKit 或 NSJSONSerialization)?