OC 底层探索 06、 isa 2个经典问题分析

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(@"\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);
        /*
          运行结果:
          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") 

--> 根据传入的字符返回类;没有则创建 

 

posted @ 2020-09-21 02:00  张张_z  阅读(251)  评论(0编辑  收藏  举报