Ios ObjC:+;[NSObject isSubclassOfClass:]给出了错误的失败
我有一个iOS静态库,它定义了一个Ios ObjC:+;[NSObject isSubclassOfClass:]给出了错误的失败,ios,objective-c,Ios,Objective C,我有一个iOS静态库,它定义了一个NSOperation基类,客户端应将其子类化以添加自己的逻辑:@interface BaseClass:NSOperation 客户机向管理器注册其子类:-[OperationManagerClass registerClass:forType:: 在管理器中,我想强制您必须注册BaseClass的子类,而不仅仅是NSOperation 好的,看来断言+isSubclassOfClass:应该可以完成任务。但是没有 @implementation Opera
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中
应用中目标
。。。传入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
参数必须是我的基类的子类?
编辑:
我意识到我发布的示例在将各个部分拉入单独的Xcode工作区后效果良好。我有一个从我的原始描述中漏掉的扭曲 我实际上有两个静态库(
libSharedStuff.a
和libHelperSharedStuff.a
)。应用程序目标链接到libSharedStuff.a
,单元测试目标取决于应用程序目标以及链接libHelperSharedStuff.a
。当BaseClass.m
是两个静态库目标的成员时,单元测试断言将失败。具体来说,当我通过MockBaseClass
时,它会失败,这是作为单元测试目标一部分的BaseClass
的子类
所有这些都在上面链接的项目中进行了说明。请确保静态库确实导致符号正确链接。我的直接猜测是,作为aClass传递的静态库提供的类在运行时实际上为零,因此对发送给它的任何消息返回0 确保这一点的一种方法是创建一个使用它们的构造函数:
__attribute__((constructor)) static void EnsureClassesAreLoaded(void) {
[BaseClass self];
}
弱链接类可能有点棘手。正如我在编辑问题时所解释的,我在静态库
libSharedStuff.a
和libhelpersaredstuff.a
中都包含了BaseClass.m
。主应用程序目标链接到libSharedStuff.a
,单元测试目标链接到libHelperSharedStuff.a
。这意味着当运行时将.xtest
捆绑包注入我的应用程序时,基类
符号被定义两次
(可能?可能吗?运行时实际发生了什么?)
我似乎在我的单元测试中,targetmocksubassofbaseclass
继承自libHelperSharedStuff.a
中的BaseClass
符号,而在我的应用程序中,targetsubassofbaseclass
继承自libSharedStuff.a
中的BaseClass
符号。如果是这种情况,那么当传入mockSubassofbaseClass
时,为什么+isSublcassOfClass:
响应NO
,这是有道理的
如果您的回答能够澄清、确认或提供更好的见解,说明我的想法是正确的,我们将不胜感激。如果您正在使用可可豆豆,请确保您没有将所有可可豆豆链接到测试目标
这就解决了我的问题。如何解决:
NSAssert([aClass.superclass isKindOfClass[BaseClass]])
紧张地坐立不安。。。我考虑过,但这与我真正想要的略有不同。另外,我认为它应该是NSAssert([aClass superclass]==[BaseClass])
但不要让我这么认为!:-)当然,您可以检查是否有任何超类是正确的类型。这将为您提供相当于检查超类的逻辑。如果[NSObject isSubclassOfClass::
拒绝很好地发挥作用,您可以这样实现自己的:)您的意思是Baseclass.m在两个静态库项目中吗?嗯,有趣的想法。我不确定我在这里是否有足够的专业知识,但是nm libSharedStuff.a
确实打印U\U OBJC\U CLASS\U$\ U BaseClass
,S\U OBJC\U元类\U$\ U BaseClass
和(BaseClass.o):
。。。同样,我不在我的舒适区w/nm,但我认为这意味着静态库是好的?这不是关于静态库,而是关于确保静态库实际链接到您的应用程序。如果你的应用程序没有对库中的任何符号进行硬引用,那么库可能根本不会链接。bbum:进一步说,它可以链接进来,而不是将所有符号都带进来,不是吗?虽然这可能只适用于类别,但现在我想起来了;死代码剥离,或多或少?一个应用程序中可能加载两个同名的类。如果是这样的话,运行时应该抱怨(请检查Organizer中的调试器控制台和设备控制台)。
(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
__attribute__((constructor)) static void EnsureClassesAreLoaded(void) {
[BaseClass self];
}