zoukankan      html  css  js  c++  java
  • 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") 

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

     

  • 相关阅读:
    JS 数字时钟的代码(摘录,忘了是从哪了)
    数据写入DataTable C# 2005
    C# 进制转化问题测试下再说(网上的直接转化不好用)
    防sql 注入,就是将sql 的执行命令给排除
    今天研究了一下午网站窄屏/宽屏的切换实现
    解决VS2005下中文输入法全角半角混乱的补丁
    一些实用的站长查询工具
    UE(用户体验)无处不在,留心处处皆学问
    添加了方便聚合的链接
    该好好整理一下自己了
  • 原文地址:https://www.cnblogs.com/zhangzhang-y/p/13701911.html
Copyright © 2011-2022 走看看