iOS底层:isa面试题

465 阅读2分钟

面试题涉及的知识点,都还在经典的isa&继承链图:


面试题:

以下关于isKindOfClassisMemberOfClass的类方法、实例方法的结果解析:

// 类方法
BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];       //
BOOL re2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];     //
BOOL re3 = [(id)[LGPerson class] isKindOfClass:[LGPerson class]];       //
BOOL re4 = [(id)[LGPerson class] isMemberOfClass:[LGPerson class]];     //
NSLog(@"\n re1 :%hhd\n re2 :%hhd\n re3 :%hhd\n re4 :%hhd\n",re1,re2,re3,re4);

// 实例方法
BOOL re5 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]];       //
BOOL re6 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]];     //
BOOL re7 = [(id)[LGPerson alloc] isKindOfClass:[LGPerson class]];       //
BOOL re8 = [(id)[LGPerson alloc] isMemberOfClass:[LGPerson class]];     //
NSLog(@"\n re5 :%hhd\n re6 :%hhd\n re7 :%hhd\n re8 :%hhd\n",re5,re6,re7,re8);

通过查找源码,可以看到这两个方法的实现:

1. isKindOfClass

+ (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = self->ISA(); tcls; tcls = tcls->superclass) {
        if (tcls == cls) return YES;
    }
    return NO;
}

- (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
        if (tcls == cls) return YES;
    }
    return NO;
}

但是我们在断点调试过程中,发现isKindOf的类方法和实例方法,并没有被调用.其实是被llvm做了底层逻辑优化,调用的方法会进入到objc_opt_isKindOfClass.

// Calls [obj isKindOfClass]
BOOL
objc_opt_isKindOfClass(id obj, Class otherClass)
{
#if __OBJC2__
    if (slowpath(!obj)) return NO;
    Class cls = obj->getIsa();
    if (fastpath(!cls->hasCustomCore())) {
        for (Class tcls = cls; tcls; tcls = tcls->superclass) {
            if (tcls == otherClass) return YES;
        }
        return NO;
    }
#endif
    return ((BOOL(*)(id, SEL, Class))objc_msgSend)(obj, @selector(isKindOfClass:), otherClass);
}

通过源码,我们可以看到,isKindOf方法的内部逻辑是当前类指向的元类的继承链 与 要对比的类 进行比较


isKindOf类方法调用过程:

BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];  
/*
1.NSObject的的元类是根元类==>tcls,tcls与NSObject对比为NO,tcls赋值根元类的父类
2.根元类的父类为根类==>tcls,tcls与NSObject对比为YES
*/

BOOL re3 = [(id)[LGPerson class] isKindOfClass:[LGPerson class]];  
/*
1.LGPerson的元类为元类LGPerson==>tcls,tcls与LGPerson对比为NO,tcls赋值元类LGPerson的父类
2.元类LGPerson的父类为根元类==>tcls,tcls与LGperson对比为NO,tcls赋值根元类的父类
3.根元类的父类为根类NSObject==>tcls,tcls与LGPerson对比为NO,tcls赋值根类的父类nil
*/    

2.isMemberOfClass

+ (BOOL)isMemberOfClass:(Class)cls {
    return self->ISA() == cls;
}

- (BOOL)isMemberOfClass:(Class)cls {
    return [self class] == cls;
}     

isMemberOfClass类方法,是当前类对象的元类与其进行对比是否相等;

isMemberOfClass实例方法,是当前实例对象的类与其进行对比是否相等

所以面试题的结果为:

 re1 :1
 re2 :0
 re3 :0
 re4 :0
 re5 :1
 re6 :1
 re7 :1
 re8 :1


补充

+ (Class)class {
    return self;
}

- (Class)class {
    return object_getClass(self);
}

Class object_getClass(id obj)
{
    if (obj) return obj->getIsa();
    else return Nil;
}