iOS 类的数据结构

2020/4/22 23:22:00

本文主要是介绍iOS 类的数据结构,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

数据结构

Class 就是结构体 objc_class

内部结构如下,需要注意的是objc_class继承自objc_object,那么里面就应该有一个isa

参数名 类型 作用
isa Class isa指针,指向元类
superclass Class 父类
chache cache_t 方法缓存,大小由内部成员决定
bits class_data_bits_t 存储了一些数据
data class_rw_t 获取bits里存储的data

1、isa

具体请看 isa详解

2、superclass

看变量名就知道这是父类对象,不需要过多解释

3、cache 方法缓存

cache顾名思义是缓存

参数名 类型 大小 作用
_buckets 数组 8字节 存储一个个结构体bucket_t
_mask mask_t,实际就是uint32_t 4字节 掩码
_occupied mask_t,实际就是uint32_t 4字节 已缓存的数量

接下来看bucket_t是什么,bucket_t有2个成员变量_impkey,这不用多说肯定是方法和关键值。那么我们就可以猜想,是不是能根据key获取到对应的IMP,进行方法调用?至此也确定了cache里缓存的是方法。

4、bitsdata

可以看到bits是一个64位的数据段,那么里面存了什么数据呢?

bits下面紧接了一个data的声明,返回的正是bits里面的数据。但是类型是class_rw_t

4-1 class_rw_t 结构

methods方法、properties属性、protocols协议,都是我们平常在声明类的时候能看到的,感觉相当熟悉。但是里面还有一个class_ro_t类型的成员变量ro引起了我的注意

4-2 class_ro_t 结构

ro里也有方法、属性、协议,还有实例变量,这是为什么呢?

4-3 探索 class_rw_t

LGPerson如下

执行代码打印获取到LGPerson类的结构,可以直接看到isasuperClass。但是怎么获取class_rw_tclass_ro_t 呢?

通过isa地址向右偏移32位可以获取到bits

输出methods,看到数量为4,存储了我们声明的sayHello方法以及nickNamesetter、getter方法,但是并没有看到sayHappy方法?

输出properties可以看到我们声明的nickName属性,符合我们的预期

输出protrols,里面是空的,也符合预期

至此,对比LGPerson文件我们还没有看到sayHappy方法和成员变量hobby,猜测它们又被存储在哪里呢?来输出ro看看

输出baseMethodList可以看到里面的内容和rwmethods是一样的,没有sayHappy方法

输出baseProperties,很可惜依旧没有找到hobby

输出ivars,可以看到count为2,单独输出以后我们可以看到hobby_nickName都在其中

4-4、类方法存储

sayHappy方法到底去哪里了?sayHappysayHello 区别在于 sayHello 是实例方法, sayHappy 是类方法。这说明了实例方法存储在类对象中,类方法不存储在类对象中。

那么类方法存在哪里呢?大胆猜测一下类方法会不会存在元类对象中呢?接下来去元类中寻找一下。

输出元类的方法列表

4-5、bitsro数据重复问题

bits里面存储了方法列表、属性列表等成员变量,为什么还需要ro再存储一份?

objc_class结构中的data()方法可以返回bits的信息,那么我们便可以通过setData()向上查找调用方看看class赋值流程,也许就能解开这个问题。

找到编译期间执行的realizeClass方法,这里应该就是最初的地方。 但这里并没有对rw里面的列表赋值,编译期间rw的各个列表应该是空值!

那么rw的数据又是从哪里来的呢?这就涉及到了methodizeClass方法,就是它向rw中添加类的方法列表、协议列表、属性列表。

执行了methodizeClassro中的属性、对象方法,协议都添加到了rw中。这样在class_rw_t结构中可以拿到类的相关信息了。也就形成了以下结构:

虽然找到了实现,但是还是不知道为什么这么存呀。这就需要看看了realizeClass在什么时候调用了。这个时候,prepare_load_methods引起了我的注意

prepare_load_methods是加载分类时会调用的方法,结合methodizeClass我们会发现分类添加的方法统统都会加入到rw而不加入roro保留着类最原始的数据,后续改变都无法侵入它!

总结

至此,疑问已经解开,类结构已经解析完毕。

结论如下:

  • .h文件声明属性会自动生成settergetter、成员变量。
  • 实例方法存在类中,类方法存在元类中
  • 原始方法会存在ro中,分类方法存在rw


这篇关于iOS 类的数据结构的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程