发生这种情况的原因:
免责声明:
我不是静态库、链接和相关依赖项方面的专家。如果我对链接或 Cocoapods 的工作方式有任何错误,请纠正我。
对于这个Podfile,Cocoapods 构建了两个静态库——每个目标一个。
编译项目后,MyTarget 中的所有代码将链接到 LibPods-MyTarget.a 库,MyTargetTests 中的所有代码将链接到 LibPods-MyTargetTests.a 库。
它们都包含RestKit/ObjectMapping 组件的副本(因为它是RestKit 和RestKit/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 已有的功能,或者您知道任何其他解决方案,请发表评论或将其作为另一个答案发布。