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

ede*_*y05 4 objective-c ios

  • 我有一个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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

你要知道,基础操作类的消费者在iOS的应用程序项目继承,并OperationManagerClassBaseClass处于包括静态库.为什么我认为这可能与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
Run Code Online (Sandbox Code Playgroud)

在应用目标中

@interface OutsideClass : NSOperation
@end

@interface OutsideClassSubA : OutsideClass
@end
Run Code Online (Sandbox Code Playgroud)

... 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
Run Code Online (Sandbox Code Playgroud)

这里发生了什么?为什么+isSubclassOfClass:给出错误的答案?如何强制aClass参数必须是我的子类BaseClass


编辑:
我意识到我发布的示例在将各个部分拉入单独的Xcode工作区后工作正常.我已经从上面发布了玩具源代码,但是我从原始描述中遗漏了一些.

我实际上有两个静态库(libSharedStuff.alibHelperSharedStuff.a).应用程序目标链接libSharedStuff.a,单元测试目标取决于应用程序目标以及链接libHelperSharedStuff.a.如果BaseClass.m两个静态库目标的成员,则+isSubclassOfClass:单元测试断言将失败.具体来说,它在我通过时失败MockBaseClass,它是BaseClass单元测试目标的一部分.

所有这些都在上面链接的项目中说明.

ede*_*y05 7

正如我在编辑我的问题时所解释的那样,我包含BaseClass.m在静态库libSharedStuff.alibHelperSharedStuff.a.主应用程序目标链接libSharedStuff.a与单元测试目标链接libHelperSharedStuff.a.这意味着当.xctest捆绑包在运行时注入我的应用程序时,BaseClass符号定义两次

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

我似乎在我的单元测试目标中MockSubclassOfBaseClass继承了BaseClass符号libHelperSharedStuff.a,而在我的应用程序中,目标SubclassOfBaseClass继承自BaseClass符号libSharedStuff.a.如果是这种情况,那么为什么传入时会+isSublcassOfClass:响应!NOMockSubclassOfBaseClass

任何澄清,确认或提供更好的见解的答案都非常感谢我在这里得到了正确的想法.

  • 可以在应用程序中加载两个具有相同名称的类.如果是这样,运行时应该抱怨(检查管理器中的调试器控制台和设备控制台). (2认同)