【问题标题】:How to tell if a Class inherits from NSObject (Objective-C)如何判断一个类是否继承自 NSObject (Objective-C)
【发布时间】:2010-11-22 23:27:34
【问题描述】:

我在 iPhone 上使用 Objective-C,需要知道“类”是否继承自“NSObject”。

我尝试检查它是否响应 NSObject 选择器:

bool success = [myClass respondsToSelector:@selector(class)];

但你可以猜到发生了什么......它甚至没有响应“respondsToSelector:”所以它抛出了一个“不实现 doesNotRecognizeSelector:”异常。

我试图捕获该异常,但似乎无法使用 @try-@catch 捕获它。

有什么想法吗?

【问题讨论】:

  • 我认为更好的问题是您如何处理这些不继承自 NSObject 的类。除了协议之外应该没有任何其他内容。
  • 你的意思是@selector(class)。我认为 SDK 中没有任何响应 +class: 的内容。
  • 我正在创建一个库来简化序列化,这意味着我正在处理我没有创建的类。在我可以使用它之前,我至少需要验证一个类是否符合 NSObject 协议 - 否则会引发“无法捕获的异常”(如下面的 Tommy 所述)。
  • @Dave DeLong:我有点犹豫,因为 NSProxy 到 NSObject 的行为就像 NSObject。它不会产生您需要知道您拥有什么样的对象才能知道您需要发送什么消息来询问它是什么类型的对象的问题。

标签: iphone objective-c reflection nsobject


【解决方案1】:

直接进入 Objective-C 运行时:

#import <objc/runtime.h>

/* originally posted version — works because eventually class_getSuperclass(class)
returns nil, and class_getSuperclass(nil) does so also. */
BOOL classDescendsFromClass(Class classA, Class classB)
{
    while(1)
    {
        if(classA == classB) return YES;
        id superClass = class_getSuperclass(classA);
        if(classA == superClass) return (superClass == classB);
        classA = superClass;
    }
}

/* shorter version; exits straight after classA turns into nil */
BOOL classDescendsFromClassShorter(Class classA, Class classB)
{
    while(classA)
    {
        if(classA == classB) return YES;
        classA = class_getSuperclass(classA);
    }

    return NO;
}
...

if(classDescendsFromClass(classToTest->isa, [NSObject class]) ...

class_getSuperclass 言行一致,并且在 Objective-C 运行时通过指针比较元类是安全的,因为每个类只有一个元类实例。 isa 指针是唯一肯定在 struct objc_object 中的东西。

编辑:此外,iPhone 模拟器中存在已知的错误,这些错误会导致某些异常无法被 try/catch 块捕获。我已将它们作为错误报告给 Apple,并被告知我的是重复的,所以他们肯定知道。您是在真实设备上还是在模拟器中尝试了您的代码?

EDIT2:从本次对话其他地方给出的更广泛的背景来看,这样的事情可能更聪明:

#import <objc/runtime.h>

BOOL classRespondsToSelector(Class classA, SEL selector)
{
    return class_getInstanceMethod(classA, selector) ? YES : NO;
}

....
if(classRespondsToSelector(instance->isa, @selector(respondsToSelector:))
{
     // great, we've got something that responds to respondsToSelector:; do the
     // rest of our querying through there
}

【讨论】:

  • 这个答案非常好,而且效果很好。您对模拟器/设备上的 try/catch 块也是正确的。我读过 try/catch 块不应该用于控制流(在 obj-c 中),而且我不愿意失去模拟器调试,所以我会坚持这个 'getSuperclass' 概念。
  • 其实不太对;我让自己变得有点困惑——NSObject 的 isa 指针指向 NSObject(即,即使 NSObject 元类本身也是 NSObject 的子类),但 NSObject 本身并不是超类。所以 if(classA == superClass) 比必要的迭代晚了一次终止 classDescendsFromClass (因为它最终得到 nil 作为 nil 的超类)。我会修复代码。
  • 如果你更喜欢类似 Obj-C 的语法:gist.github.com/BillinghamJ/6709374
  • 您可能想使用object_getClass(classA) 而不是-&gt;isa
【解决方案2】:

您可以使用isKindOfClass:isMemberOfClass: 方法来确定一个类是另一个类的子类还是特定类。

【讨论】:

  • 这些方法是 NSObject 协议的一部分。不符合 NSObject 协议的对象可能不会响应这些消息。
  • 没错,但正如其他人所说,你为什么要处理不符合 NSObject 协议的对象?这是一个更大、更重要的问题。您没有任何理由不拥有不符合此协议的对象。
  • 如果你正在检查一个 Class 对象怎么办?
【解决方案3】:

respondsToSelector: 本身就是一个 NSObject 定义的选择器,所以你不能使用它。如果不深入了解 Objective-C 的内部结构,我认为没有办法做到这一点。

我能问一下为什么你的对象不是 NSObject 的后代吗? Apple 强烈建议您不要尝试创建它们,并且有充分的理由。

【讨论】:

  • 实际上,NSProxy 是 Apple 提供的一个类,它不继承自 NSObject。但是,它确实符合更重要的 NSObject 协议。
  • 可以合理地假设一切都会响应 NSObject 中定义的一切。 NSProxy 不会,但预计会转发给这样做的“真实”对象。
【解决方案4】:

“Class”类不继承自 NSObject。这意味着 NSObject 定义的方法(例如isKindOfClassrespondsToSelector)不能在其上使用。

首先你想用它做什么?

【讨论】:

  • -1 确实如此。 Class 是元类的一个实例,例如-NSObject 是 +NSObject 的实例,其超类是 -NSObject,因此 -NSObject 是 -NSObject 的实例。我不确定元类是哪些实例(可能也是 NSObject!),或者如果您使用不同的根类(即如果您不从 NSObject 继承)会发生什么,但元类是类方法的基础(相反到没有“自我”的静态方法)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-04
  • 1970-01-01
  • 2017-02-17
  • 2014-04-28
  • 1970-01-01
相关资源
最近更新 更多