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

时间:2014-05-25 22:17:21

标签: ios objective-c restkit cocoapods

当使用RKMappingTest对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 个答案:

答案 0 :(得分:2)

发生这种情况的原因:

  

<子>声明:
   我不是静态库,链接和相关依赖项的专家。如果我对链接或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'

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

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

但是:它仍然需要在每个构建版本上进行编译,如果您设置了-ObjC-all_load个链接器标记,那么未使用的代码将随您的应用程序一起提供。

更脏:

  

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

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

建议:

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

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

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


其他解决方案?

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