美文网首页
OC 类的底层实现

OC 类的底层实现

作者: 我是晶锅 | 来源:发表于2019-03-11 16:54 被阅读0次

    类的底层结构

    和对象的底层一样,类对象前八个字节也是存的isa指针,那么第二个字节表示什么,我们可以直接找到源码,查看类结构。

    • 很明显,第一个指针是isa(注释掉,隐藏着的)
    • 第二个是superclass
    • 第三个cache,每一个类都会有一个cache,用来存储调用过的方法等,增加性能
    • 第四个最重要,bits,里面有我们类中的主要组成部分,看下面返回了data,接下来我们就看看data中有什么东东


      image.png

    class_rw_t的结构

    bits中返回了data,data的结构是class_rw_t,我们查看其中是什么样的结构,不进去不知道,一进去吓一跳,里面全是我们这个类中重要的信息。
    调试时怎么进去呢?
    通过类对象执行偏移进去的,想要进去data中的部分,将类对象指针向前偏移两位就可以了。
    先看看其中结构吧:

    image.png

    没错,这里面有方法列表,属性列表,协议列表。
    这里需要注意一下,readonly的属性和相关不可更改的都存在这里,这里的部分是不能进行修改的,当一个类创建完成的时候。
    所以,类创建完成后,是不能添加ivar的了!


    image.png

    LLDB调试验证

    看了源码中的代码,现在我们直接通过LLDB来调试验证正确性。
    在已经导入源码的情况下,调试可以拿到底层数据结构中的对象。
    1、拿到类对象,指针偏移两位,获取到data
    2、打印data中所有数据,你能看到这个类的基本方法列表,属性列表和协议列表了


    image.png

    继续往里走,可以拿到我们自己创建的方法


    image.png
    通过这样的方式,我们还可以验证两个东西:
    • 类方法存在元类中
    • 实例方法存在类中

    打印验证方法的获取

    上面我们能够通过LLDB直接查看方法存的位置,类方法存在元类中,实例方法存在类中。(0表示有,1表示没有)
    LGPerson中书写两个方法,并实现:

    - (void)lg_instanceMethod;
    + (void)lg_classMethod;
    
    demo1:class_getInstanceMethod
        Method method1 = class_getInstanceMethod([LGPerson class], @selector(lg_instanceMethod)); // 类对象 拿 实例方法
        Method method2 = class_getInstanceMethod(objc_getMetaClass("LGPerson"), @selector(lg_instanceMethod)); // 元类对象 拿 实例方法
        Method method3 = class_getInstanceMethod([LGPerson class], @selector(lg_classMethod));
        Method method4 = class_getInstanceMethod(objc_getMetaClass("LGPerson"), @selector(lg_classMethod));
        NSLog(@"%p-%p-%p-%p",method1,method2,method3,method4);
    

    这里输出:1 0 0 1
    解释:
    对象方法是存在类中的,method1为1,method2为0;
    类方法存在元类中的,method3为0,method4为1。

    demo2:class_getMethodImplementation
        IMP imp1 = class_getMethodImplementation([LGPerson class], @selector(lg_instanceMethod));
        IMP imp2 = class_getMethodImplementation([LGPerson class], @selector(lg_classMethod));
        IMP imp3 = class_getMethodImplementation(objc_getMetaClass("LGPerson"), @selector(lg_instanceMethod));
        IMP imp4 = class_getMethodImplementation(objc_getMetaClass("LGPerson"), @selector(lg_classMethod));
        NSLog(@"%p-%p-%p-%p",imp1,imp2,imp3,imp4);
    

    这里输出:1 1 1 1
    解释:imp1 和 imp4与上面同理。为什么imp2 和 imp3也会有呢?其实类中并没有类方法,元类中也没有对象方法,只是 class_getMethodImplementation 底层会走 _objc_msgForward 方法,所以还是找到了。


    image.png
    demo3:class_getClassMethod
        Method method1 = class_getClassMethod([LGPerson class], @selector(lg_instanceMethod));
        Method method2 = class_getClassMethod(objc_getMetaClass("LGPerson"), @selector(lg_instanceMethod));
        
        // 类 --> lg_classMethod 类方法
        // 元类
        Method method3 = class_getClassMethod([LGPerson class], @selector(lg_classMethod));
        Method method4 = class_getClassMethod(objc_getMetaClass("LGPerson"), @selector(lg_classMethod));
        NSLog(@"%p-%p-%p-%p",method1,method2,method3,method4);
    

    输出:0 0 1 1
    解释:我们从底层源码中看出,class_getClassMethod 底层使用就是 class_getInstanceMethod

    Method class_getClassMethod(Class cls, SEL sel)
    {
        if (!cls  ||  !sel) return nil;
    
        return class_getInstanceMethod(cls->getMeta(), sel);
    }
    

    所以 method1 和 method2 中根本没有 lg_instanceMethod 的类方法,lg_instanceMethod 是一个对象方法。
    method3 和 method4 其实都是从元类中找寻类方法,所以当然能找到。

    添加方法,协议,属性 attachLists

    我们的类,在创建类和需要添加的时候都会调用 attachLists 方法,将我们需要添加的方法,协议,属性添加进去。具体 attachLists 是怎么实现的,接下来分解。


    image.png

    最后附上一张类的底层结构图:


    类结构.png

    相关文章

      网友评论

          本文标题:OC 类的底层实现

          本文链接:https://www.haomeiwen.com/subject/chktpqtx.html