我有一个iOS静态库,它定义了一个NSOperation
基类,客户端应该将其子类添加到自己的逻辑中:@interface BaseClass : NSOperation
客户使用经理注册其子类:-[OperationManagerClass registerClass:forType:]
在经理中,我想强制您必须注册BaseClass
的子类,而不仅仅是NSOperation
好吧,似乎断言+isSubclassOfClass:
应该完成工作。但是......事实并非如此。
@implementation OperationManagerClass
- (void)registerClass:(Class)aClass forType:(NSString *)type
{
NSAssert([aClass isSubclassOfClass:[BaseClass class]);
self.registeredClasses[type] = aClass;
}
@end
断言总是NO
,即使传递BaseClass
。
如何在班级层级中走得更远? NSOperation
和NSObject
都回复YES
!
(lldb) p (BOOL)[aClass isSubclassOfClass:[BaseClass class]]
(BOOL) $0 = NO
(lldb) po aClass
BaseClass
(lldb) p (BOOL)[aClass isSubclassOfClass:[NSOperation class]]
(BOOL) $2 = YES
(lldb) p (BOOL)[aClass isSubclassOfClass:[NSObject class]]
(BOOL) $3 = YES
请注意,基本操作类的使用者是iOS应用程序项目中的子类,OperationManagerClass
和BaseClass
位于包含的静态库中。为什么我认为这可能与isSubclassOfClass:
错误有关?由于以下原因......
仍然在libSharedStuff.a
@implementation OperationManagerClass
- (void)registerClass:(Class)aClass forType:(NSString *)type
{
// Obviously OperationManagerClass.m cannot #import "OutsideClass.h"
NSAssert([aClass isSubclassOfClass:NSClassFromString(@"OutsideClass");
self.registeredClasses[type] = aClass;
}
@end
在应用程序目标
中@interface OutsideClass : NSOperation
@end
@interface OutsideClassSubA : OutsideClass
@end
...传递OutsideClassSubA
时产生以下结果:
(lldb) p (BOOL)[aClass isSubclassOfClass:[OutsideClass class]]
(BOOL) $0 = YES
(lldb) po aClass
OutsideClassSubA
(lldb) p (BOOL)[aClass isSubclassOfClass:[NSOperation class]]
(BOOL) $2 = YES
(lldb) p (BOOL)[aClass isSubclassOfClass:[NSObject class]]
(BOOL) $3 = YES
这里发生了什么?为什么+isSubclassOfClass:
会给出错误的答案?如何强制aClass
参数必须是我BaseClass
的子类?
<小时/> 编辑:
我实际上有两个静态库(libSharedStuff.a
和libHelperSharedStuff.a
)。应用程序目标与libSharedStuff.a
链接,单元测试目标取决于应用程序目标以及链接libHelperSharedStuff.a
。当BaseClass.m
是两个静态库目标的成员时,+isSubclassOfClass:
将在单元测试断言中失败。具体来说,当我通过MockBaseClass
时,它会失败,BaseClass
是{{1}}的子类,它是单元测试目标的一部分。
所有这些都在上面链接的项目中说明。
答案 0 :(得分:7)
正如我在编辑问题时所解释的那样,我在BaseClass.m
和libSharedStuff.a
两个静态库中都包含libHelperSharedStuff.a
。主要应用程序目标链接libSharedStuff.a
,单元测试目标链接libHelperSharedStuff.a
。这意味着当.xctest
包在运行时注入我的应用程序时,BaseClass
符号被定义两次
(也许?这可能吗?运行时实际发生了什么?)。
我似乎在我的单元测试目标MockSubclassOfBaseClass
中继承了BaseClass
中的libHelperSharedStuff.a
符号,而在我的应用中,目标SubclassOfBaseClass
继承自BaseClass
libSharedStuff.a
中的符号。如果是这种情况,则+isSublcassOfClass:
传递NO
时MockSubclassOfBaseClass
响应{{1}}是有道理的。
任何能够澄清,确认或提供更好洞察力的答案我都非常感激。
答案 1 :(得分:1)
确保静态库实际上导致符号正确链接。我的直接猜测是,作为aClass传递的静态lib提供的类在运行时实际上是Nil,因此向发送它的任何消息返回0。
确保这一点的一种方法是创建一个使用它们的构造函数:
__attribute__((constructor)) static void EnsureClassesAreLoaded(void) {
[BaseClass self];
}
弱链接类可能有点棘手。
答案 2 :(得分:1)
如果您使用的是可可豆荚,请确保没有将所有豆荚链接到测试目标。
这解决了我的问题。