How to tell if a Class inherits from NSObject (Objective-C)

前端 未结 4 1023
小鲜肉
小鲜肉 2021-01-06 12:29

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

I tried checking if it responds to an NSObject selector:

4条回答
  •  没有蜡笔的小新
    2021-01-06 12:48

    Go direct to the Objective-C runtime:

    #import 
    
    /* 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.

    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?

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

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

提交回复
热议问题