几道isa相关的经典面试题以及分析
@interface HRTest : NSObject
- (void)sayHello;
+ (void)sayHappy;
@endHRTest *test = [HRTest alloc];
Class pClass = object_getClass(test);
const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className); //原类
Method method1 = class_getInstanceMethod(pClass, @selector(sayHello));
Method method2 = class_getInstanceMethod(metaClass, @selector(sayHello));
Method method3 = class_getInstanceMethod(pClass, @selector(sayHappy));
Method method4 = class_getInstanceMethod(metaClass, @selector(sayHappy));
NSLog(@"%p-%p-%p-%p",method1,method2,method3,method4);输出结果:

class_getInstanceMethod获取当前类的实例方法实例方法存在类中,类方法存在元类中const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className); //元类
Method method1 = class_getClassMethod(pClass, @selector(sayHello));
Method method2 = class_getClassMethod(metaClass, @selector(sayHello));
Method method3 = class_getClassMethod(pClass, @selector(sayHappy));
Method method4 = class_getClassMethod(metaClass, @selector(sayHappy));
NSLog(@"%s-%p-%p-%p-%p",__func__,method1,method2,method3,method4);输出结果:

class_getClassMethod获取当前类的类方法sayHello是实例方法,不可能找到,sayHappy是类方法,自然存在于当前类中。可是当前类的元类中不可能存在该类方法,查看该方法实现的源码。class_getClassMethod的方法实现Method class_getClassMethod(Class cls, SEL sel)
{
if (!cls || !sel) return nil;
return class_getInstanceMethod(cls->getMeta(), sel);
}
Class getMeta() {
if (isMetaClass()) return (Class)this;
else return this->ISA();
}类方法在底层中的存在形式:元类中的实例方法。(c、c++中并没有实例、类方法)碰到元类会直接返回当前元类,并不会继续查找向上查找(元类的isa指向根源类)。metaClass已经是元类了,无需找到根源类了;第三步、第四步等价。实例方法存在类中,类方法存在元类中。
IMP imp1 = class_getMethodImplementation(pClass, @selector(sayHello));
IMP imp2 = class_getMethodImplementation(metaClass, @selector(sayHello));
IMP imp3 = class_getMethodImplementation(pClass, @selector(sayHappy));
IMP imp4 = class_getMethodImplementation(metaClass, @selector(sayHappy));
IMP class_getMethodImplementation(Class cls, SEL sel)
{
IMP imp;
if (!cls || !sel) return nil;
imp = lookUpImpOrNil(nil, sel, cls, LOOKUP_INITIALIZE | LOOKUP_RESOLVER); //先找缓存cache_t,然后去cls->data()->methods()中查找
if (!imp) {
return _objc_msgForward; //找不到回到这里
}
return imp;
}cache_t中找,然后去cls->data()->methods()中查找,最后会进入_objc_msgForward流程.0x100001d00-0x7fff6c018580-0x7fff6c018580-0x100001d30
(lldb) p/x imp1
(IMP) $0 = 0x0000000100001d00 (002-类方法归属分析`-[LGPerson sayHello] at LGPerson.m:13)
(lldb) p/x imp4
(IMP) $1 = 0x0000000100001d30 (002-类方法归属分析`+[LGPerson sayHappy] at LGPerson.m:17)
(lldb) p/x imp2
(IMP) $2 = 0x00007fff6c018580 (libobjc.A.dylib`_objc_msgForward)0x00007fff6c018580不该存在的这个地址是:_objc_msgForward流程!!并不是找到真的方法!!!BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];
BOOL re2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];
BOOL re3 = [(id)[HRTest class] isKindOfClass:[HRTest class]];
BOOL re4 = [(id)[HRTest class] isMemberOfClass:[HRTest class]];输出结果:

+isKindOfClass类方法:+ (BOOL)isKindOfClass:(Class)cls {
//使用调用者的isa和当前入参对比。
for (Class tcls = self->ISA(); tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}事实上这个方法并不会被调用,而是由llvm处理为调用objc_opt_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->getSuperclass()) {
if (tcls == otherClass) return YES;
}
return NO;
}
#endif
return ((BOOL(*)(id, SEL, Class))objc_msgSend)(obj, @selector(isKindOfClass:), otherClass);
}循环:
第一次循环:NSObject的isa -> 根元类 与 NSObject不相同
第二次循环:根元类的superclass -> NSObject 与NSObject相同
所以是通过根元类的父类又回到NSObject这条线找到的,其他类没有这个特性。
+isMemberOfClass类方法:+ (BOOL)isMemberOfClass:(Class)cls {
return self->ISA() == cls;
}拿当前类的isa指向和参数做对比,相同的类一定不相等.
BOOL re5 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]]; //
BOOL re6 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]]; //
BOOL re7 = [(id)[HRTest alloc] isKindOfClass:[LGPerson class]]; //
BOOL re8 = [(id)[HRTest alloc] isMemberOfClass:[LGPerson class]]; 
-isKindOfClass- (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}-isMemberOfClass- (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
}这道题很简单,现实面试应该是碰不到这样的题目。
+ (Class)class {
return self;
}
- (Class)class {
return object_getClass(self);
}
Class object_getClass(id obj)
{
if (obj) return obj->getIsa();
else return Nil;
}isa找类。objc_object 、objc_class、 NSObject、类之间的关系
NSObject是OC中对象的基类;objc_object是C++/C中对象的基类,更偏向底层。对象,而对象都是继承自objc_object,包括objc_class objc_class是所有类的基类属性 、 成员变量 、 实例变量区别
实例变量+非实例变量组成