类的底层结构
和对象的底层一样,类对象前八个字节也是存的isa指针,那么第二个字节表示什么,我们可以直接找到源码,查看类结构。
- 很明显,第一个指针是isa(注释掉,隐藏着的)
- 第二个是superclass
- 第三个cache,每一个类都会有一个cache,用来存储调用过的方法等,增加性能
-
第四个最重要,bits,里面有我们类中的主要组成部分,看下面返回了data,接下来我们就看看data中有什么东东
image.png
class_rw_t的结构
bits中返回了data,data的结构是class_rw_t,我们查看其中是什么样的结构,不进去不知道,一进去吓一跳,里面全是我们这个类中重要的信息。
调试时怎么进去呢?
通过类对象执行偏移进去的,想要进去data中的部分,将类对象指针向前偏移两位就可以了。
先看看其中结构吧:
没错,这里面有方法列表,属性列表,协议列表。
这里需要注意一下,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
网友评论