当前位置: 首页 > 科技观察

Runtime系列(数据结构解析)

时间:2023-03-18 16:45:14 科技观察

上一篇提到了类和元类。我们已经知道类的本质就是objc_class这个结构体。接下来我们看看objc_class是什么。objc_class.pngisa指向元类,super_class表示当前类的父类,这两个成员我们已经很熟悉了,这里不再赘述(参见类和元类,引用)。name:类名version:版本相关信息,默认为0info:运行时使用的标识符instance_size:当前类实例变量(包括父类)的大小ivars从objc_class可以看出,ivars是指针对结构体objc_ivar_list和objc_ivar_list以及objc_ivar.png结构体的成员,名字大家都很熟悉,就不一一解释了。可见ivars实际上是一个链表,存储了类中成员变量的信息。其中Ivar.pngmethodLists从objc_class可以看出,methodLists是结构体objc_method_list的二级指针objc_method_liist和objc_method.png,也可以看出结构体的自嵌套,可见methodLists也是一个链表,它存储类中与方法相关的信息。因为是二级指针,类中的方法可以动态修改,这也是分类的实现原理。其中Method.png这里是对SEL和IMP的解释:什么是SEL?获取方法对应的ID。方法对应的ID是什么?可以理解为方法名的映射。看下面的例子-(void)helloWorld:(int)flag;-(void)helloWorld:(float)flag;在OC中这样会报错,错误类型为重复声明。如果你这样写:-(int)helloWorld:(int)flag;-(浮动)helloWorld:(浮动)标志;即使返回值不同,也依然是重复声明。因为他们的方法名相同,都是helloWorld:,所以这四个方法对应同一个SEL。但是这是同一个班级,如果是不同班级呢?无论是在同一个类中还是在不同的类中,只要方法名相同,SEL是一样的,得到的ID也是一样的。由于相同的方法名意味着相同的ID,如果两个非继承类中存在相同方法名的方法,如何判断该类中的方法执行呢?我们回头看看引文中提到的函数idobjc_msgSend(idself,SELop,...)[receivermessage]还是有receiver的。即使ID相同,不同的接收者仍然有不同的定位方法,允许存在相同方法名的不同Method,从而确定唯一性。IMP相对于SEL,IMP要清爽很多。IMP的本质是一个函数指针,通过IMP可以直接找到各种方法。这样效率更高,因为消息传递阶段被绕过并且位置是直接的。回到objc_class。缓存和协议不再深入,这里只是简单介绍缓存缓存也是一个链表,里面存放的是已经调用过的方法的信息,这样常用的方法就可以存放在缓存中,可以提高查找方法的效率。protocolsprotocols仍然是一个链表,存放的是当前类(包括父类)遵循的协议信息。