isa 2 个经典问题分析
一、类的归属问题
1、2 个 API
objc_getMetaClass() –> 获取元类

class_getMethodImplementation() –> 获取 IMP

2、实例方法 和 类方法 分析
1. 实例方法
class_getInstanceMethod() –> 类的实例方法

2. 类方法
class_getClassMethod() –> class_getInstanceMethod(cls->getMeta(), sel)
从源码可知,获取类方法,即 获取元类的实例方法 <– class_getInstanceMethod(metalCls,sel);

如上 getMeta() 方法,判断如果是元类指直接 return。
之前文章 类的结构分析 中我们已知 isa 走向流程:元类指向根元类,根元类指向自身。
getMeta() 方法当是根元类时,此时便不需要再返回 ISA 了,因为,如果不做限制,那么走到根元类处,将会形成无限递归死循环。这自然是不合理的。而类方法存在元类中,我们已经找到元类处了,也同样不必再向上寻找。
示例代码:
1 2 3 4 5 6 7
| int main(int argc, const char * argv[]) { MYPerson *person = [MYPerson alloc]; Class pClass = object_getClass(person);
myInstanceMethod_classToMetaclass(pClass);
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| void myInstanceMethod_classToMetaclass(Class pClass){ const char *className = class_getName(pClass); Class metaClass = objc_getMetaClass(className); Method method1 = class_getInstanceMethod(pClass, @selector(sayInstance)); Method method2 = class_getInstanceMethod(metaClass, @selector(sayInstance));
Method method3 = class_getInstanceMethod(pClass, @selector(sayClass)); Method method4 = class_getInstanceMethod(metaClass, @selector(sayClass)); NSLog(@"%s - %p-%p-%p-%p",__func__,method1,method2,method3,method4); }
void myClassMethod_classToMetaclass(Class pClass){ const char *className = class_getName(pClass); Class metaClass = objc_getMetaClass(className); Method method1 = class_getClassMethod(pClass, @selector(sayInstance)); Method method2 = class_getClassMethod(metaClass, @selector(sayInstance));
Method method3 = class_getClassMethod(pClass, @selector(sayClass)); Method method4 = class_getClassMethod(metaClass, @selector(sayClass)); NSLog(@"%s-%p-%p-%p-%p",__func__,method1,method2,method3,method4); }
|
执行结果:
运行 1 结果: - 实例方法
1 2 3
| myInstanceMethod_classToMetaclass - 0x1000031b0-0x0-0x0-0x100003148 // 1 0 0 1
|
运行 2 结果: - 类方法
1 2 3
| myClassMethod_classToMetaclass- 0x0-0x0-0x100003148-0x100003148 // 0 0 1 1
|
二、isKindOf & isMemberOfClass
1、isKindOf 源码

+(BOOL)isKindOf() –> 当前类的 isa 元类是否 和 cls 类 相同,一直向上取父类 –> 当前 类的元类 或 元类父类 –> 根元类的父类 NSObject 类
-(BOOL)isKindOf() –> 当前对象的类 是否 和 cls 类 相同,一直向上取父类 –> 当前 实例对象的类 / 父类 –>
2、isMemberOfClass 源码

+(BOOL)isMemberOfClass() –> 当前类的元类
-(BOOL)isMemberOfClass() –> 当前对象的类
3、class 源码


类的 class 是自己;
实例对象的 class 是实例对象的 isa.
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| int main(int argc, const char * argv[]) { @autoreleasepool { BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]]; BOOL re2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]]; BOOL re3 = [(id)[MyPerson class] isKindOfClass:[MyPerson class]]; BOOL re4 = [(id)[MyPerson class] isMemberOfClass:[MyPerson 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)[MyPerson alloc] isKindOfClass:[MyPerson class]]; BOOL re8 = [(id)[MyPerson alloc] isMemberOfClass:[MyPerson class]]; NSLog(@"\n re5 :%hhd\n re6 :%hhd\n re7 :%hhd\n re8 :%hhd\n",re5,re6,re7,re8);
} return 0; }
|
运行上面代码,会发现无论是实例还是类方法都没有走进 isKindOfClass 中的断点???LLVM 在编译时做了编译优化。
通过调试可知走到了:objc_opt_isKindOfClass 中:

流程: 顺着继承链向上走 –> superclass
类对象的流程:类对象的 isa –> 元类 –> 根元类 –> NSobject
实例对象流程:实例对象 isa –> 类 –> 父类 –> 父… 类 –> 根类 NSObject
扩展
object_getClass(id obj) 和 objc_getClass(const char *aClassName)
object_getClass() –> isa

objc_getClass(“ClassFromStr”)
–> 根据传入的字符,返回类;没有则创建
