• 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(@"
     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") 

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

     

  • 相关阅读:
    不务正业系列-浅谈《过气堡垒》,一个RTS玩家的视角
    [LeetCode] 54. Spiral Matrix
    [LeetCode] 40. Combination Sum II
    138. Copy List with Random Pointer
    310. Minimum Height Trees
    4. Median of Two Sorted Arrays
    153. Find Minimum in Rotated Sorted Array
    33. Search in Rotated Sorted Array
    35. Search Insert Position
    278. First Bad Version
  • 原文地址:https://www.cnblogs.com/zhangzhang-y/p/13701911.html
Copyright © 2020-2023  润新知