Ios ObjC:+;[NSObject isSubclassOfClass:]给出了错误的失败

Ios ObjC:+;[NSObject isSubclassOfClass:]给出了错误的失败,ios,objective-c,Ios,Objective C,我有一个iOS静态库,它定义了一个NSOperation基类,客户端应将其子类化以添加自己的逻辑:@interface BaseClass:NSOperation 客户机向管理器注册其子类:-[OperationManagerClass registerClass:forType:: 在管理器中,我想强制您必须注册BaseClass的子类,而不仅仅是NSOperation 好的,看来断言+isSubclassOfClass:应该可以完成任务。但是没有 @implementation Opera

我有一个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中

    应用中目标

    。。。传入
    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
    捆绑包注入我的应用程序时,
    基类
    符号被定义两次

    (可能?可能吗?运行时实际发生了什么?)

    我似乎在我的单元测试中,target
    mocksubassofbaseclass
    继承自
    libHelperSharedStuff.a
    中的
    BaseClass
    符号,而在我的应用程序中,target
    subassofbaseclass
    继承自
    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];
    }