面试题涉及的知识点,都还在经典的isa&继承链图:
面试题:
以下关于isKindOfClass和isMemberOfClass的类方法、实例方法的结果解析:
// 类方法
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;
}