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 了,因为,如果不做限制,那么走到根元类处,将会形成无限递归死循环。这自然是不合理的。而类方法存在元类中,我们已经找到元类处了,也同样不必再向上寻找。
示例代码:
int main(int argc, const char * argv[]) { MYPerson *person = [MYPerson alloc]; Class pClass = object_getClass(person); myInstanceMethod_classToMetaclass(pClass);// 运行2 // myClassMethod_classToMetaclass(pClass);// 运行1 }
// 获取实例方法 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)); // 元类 为什么有 sayClass 类方法 // --> 类方法 ==》元类的实例方法 Method method4 = class_getClassMethod(metaClass, @selector(sayClass)); NSLog(@"%s-%p-%p-%p-%p",__func__,method1,method2,method3,method4); }
执行结果:
运行1 结果: - 实例方法
myInstanceMethod_classToMetaclass - 0x1000031b0-0x0-0x0-0x100003148 // 1 0 0 1
运行2结果: - 类方法
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.
代码示例:
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(@" re1 :%hhd re2 :%hhd re3 :%hhd re4 :%hhd ",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(@" re5 :%hhd re6 :%hhd re7 :%hhd re8 :%hhd ",re5,re6,re7,re8); /* 运行结果: re1 :1 re2 :0 re3 :0 re4 :0 ------------------------ re5 :1 re6 :1 re7 :1 re8 :1 */ } 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")
--> 根据传入的字符,返回类;没有则创建