如何判断一个类是否继承自NSObject (Objective-C)

时间:2021-03-07 20:13:00

I'm working in Objective-C on the iPhone and need to know whether a 'Class' inherits from 'NSObject'.

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

I tried checking if it responds to an NSObject selector:

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

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

but you can guess what happened... it didn't even respond to "respondsToSelector:" so it throws a "does not implement doesNotRecognizeSelector:" exception.

但是你可以猜到发生了什么……它甚至没有响应"respondsToSelector:"因此它抛出"does notrecognizeselector:" exception "。

I tried to catch that exception, but it looks like it can't be caught with a @try-@catch.

我试图捕获这个异常,但是看起来它不能被@try-@catch捕获。

Any ideas?

什么好主意吗?

4 个解决方案

#1


7  

Go direct to the Objective-C runtime:

直接到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 does what it says, and it's safe to compare metaclasses by pointer in the Objective-C runtime because there is only exactly one instance of the metaclass for each class. The isa pointer is the only thing that's definitely in struct objc_object.

class_getSuperclass实现了它所说的,在Objective-C运行时通过指针比较元类是安全的,因为每个类只有一个元类实例。isa指针是唯一明确存在于struct objc_object中的东西。

EDIT: additionally, there are known bugs in the iPhone simulator that cause some exceptions not to be caught by try/catch blocks. I've reported them as a bug to Apple and been told that mine was a duplicate, so they are definitely aware. Did you try your code on a real device or just in the simulator?

编辑:此外,iPhone模拟器中有一些已知的bug,导致一些异常不会被try/catch块捕获。我曾向苹果报告过它们是一个bug,并被告知我的是一个副本,所以他们肯定知道。你试过你的代码在一个真实的设备上还是仅仅在模拟器上?

EDIT2: from the wider context given elsewhere in this conversation, something like this might be smarter:

从对话中其他地方给出的更广泛的背景来看,类似这样的东西可能更聪明:

#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
}

#2


4  

You can use the methods isKindOfClass: and isMemberOfClass: to determine whether a class is a subclass of another class or if it is a particular class.

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

#3


1  

respondsToSelector: is itself an NSObject-defined selector, so you can't use it. I don't believe there's a way to do this without getting very deep into the internals of Objective-C.

respondsToSelector:本身就是一个nsobject定义的选择器,所以你不能使用它。我不相信有一种方法可以不深入到Objective-C的内部。

May I ask why you have objects that aren't descendants of NSObject? Apple very strongly recommends you don't attempt to create them, and with good reason.

我可以问一下,为什么你的对象不是NSObject的后代?苹果强烈建议你不要尝试去创造它们,而且要有充分的理由。

#4


-3  

The class 'Class' does not inherit from NSObject. That means methods defined by NSObject (such as isKindOfClass or respondsToSelector) cannot be used on it.

类“类”不从NSObject继承。这意味着NSObject(如isKindOfClass或respondsToSelector)定义的方法不能在其上使用。

What are you trying to do with it in the first place?

首先,你想用它做什么?

#1


7  

Go direct to the Objective-C runtime:

直接到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 does what it says, and it's safe to compare metaclasses by pointer in the Objective-C runtime because there is only exactly one instance of the metaclass for each class. The isa pointer is the only thing that's definitely in struct objc_object.

class_getSuperclass实现了它所说的,在Objective-C运行时通过指针比较元类是安全的,因为每个类只有一个元类实例。isa指针是唯一明确存在于struct objc_object中的东西。

EDIT: additionally, there are known bugs in the iPhone simulator that cause some exceptions not to be caught by try/catch blocks. I've reported them as a bug to Apple and been told that mine was a duplicate, so they are definitely aware. Did you try your code on a real device or just in the simulator?

编辑:此外,iPhone模拟器中有一些已知的bug,导致一些异常不会被try/catch块捕获。我曾向苹果报告过它们是一个bug,并被告知我的是一个副本,所以他们肯定知道。你试过你的代码在一个真实的设备上还是仅仅在模拟器上?

EDIT2: from the wider context given elsewhere in this conversation, something like this might be smarter:

从对话中其他地方给出的更广泛的背景来看,类似这样的东西可能更聪明:

#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
}

#2


4  

You can use the methods isKindOfClass: and isMemberOfClass: to determine whether a class is a subclass of another class or if it is a particular class.

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

#3


1  

respondsToSelector: is itself an NSObject-defined selector, so you can't use it. I don't believe there's a way to do this without getting very deep into the internals of Objective-C.

respondsToSelector:本身就是一个nsobject定义的选择器,所以你不能使用它。我不相信有一种方法可以不深入到Objective-C的内部。

May I ask why you have objects that aren't descendants of NSObject? Apple very strongly recommends you don't attempt to create them, and with good reason.

我可以问一下,为什么你的对象不是NSObject的后代?苹果强烈建议你不要尝试去创造它们,而且要有充分的理由。

#4


-3  

The class 'Class' does not inherit from NSObject. That means methods defined by NSObject (such as isKindOfClass or respondsToSelector) cannot be used on it.

类“类”不从NSObject继承。这意味着NSObject(如isKindOfClass或respondsToSelector)定义的方法不能在其上使用。

What are you trying to do with it in the first place?

首先,你想用它做什么?