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个成员变量_imp
和key
,这不用多说肯定是方法和关键值。那么我们就可以猜想,是不是能根据key
获取到对应的IMP
,进行方法调用?至此也确定了cache里缓存的是方法。
4、bits
和 data
可以看到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
类的结构,可以直接看到isa
和superClass
。但是怎么获取class_rw_t
和class_ro_t
呢?
通过isa
地址向右偏移32位可以获取到bits
输出methods
,看到数量为4,存储了我们声明的sayHello
方法以及nickName
的setter、getter
方法,但是并没有看到sayHappy
方法?
输出properties
可以看到我们声明的nickName
属性,符合我们的预期
输出protrols
,里面是空的,也符合预期
至此,对比LGPerson
文件我们还没有看到sayHappy
方法和成员变量hobby
,猜测它们又被存储在哪里呢?来输出ro
看看
输出baseMethodList
可以看到里面的内容和rw
的methods
是一样的,没有sayHappy
方法
输出baseProperties
,很可惜依旧没有找到hobby
输出ivars
,可以看到count
为2,单独输出以后我们可以看到hobby
和_nickName
都在其中
4-4、类方法存储
sayHappy
方法到底去哪里了?sayHappy
和sayHello
区别在于 sayHello
是实例方法, sayHappy
是类方法。这说明了实例方法存储在类对象中,类方法不存储在类对象中。
那么类方法存在哪里呢?大胆猜测一下类方法会不会存在元类对象中呢?接下来去元类中寻找一下。
输出元类的方法列表
4-5、bits
和ro
数据重复问题
bits
里面存储了方法列表、属性列表等成员变量,为什么还需要ro
再存储一份?
objc_class
结构中的data()
方法可以返回bits
的信息,那么我们便可以通过setData()
向上查找调用方看看class
赋值流程,也许就能解开这个问题。
找到编译期间执行的realizeClass
方法,这里应该就是最初的地方。
但这里并没有对rw
里面的列表赋值,编译期间rw
的各个列表应该是空值!
那么rw的数据又是从哪里来的呢?这就涉及到了methodizeClass
方法,就是它向rw
中添加类的方法列表、协议列表、属性列表。
执行了methodizeClass
后ro
中的属性、对象方法,协议都添加到了rw
中。这样在class_rw_t
结构中可以拿到类的相关信息了。也就形成了以下结构:
虽然找到了实现,但是还是不知道为什么这么存呀。这就需要看看了realizeClass
在什么时候调用了。这个时候,prepare_load_methods
引起了我的注意
prepare_load_methods
是加载分类时会调用的方法,结合methodizeClass
我们会发现分类添加的方法统统都会加入到rw
而不加入ro
。ro
保留着类最原始的数据,后续改变都无法侵入它!
总结
至此,疑问已经解开,类结构已经解析完毕。
结论如下:
.h
文件声明属性会自动生成setter
、getter
、成员变量。- 实例方法存在类中,类方法存在元类中
- 原始方法会存在
ro
中,分类方法存在rw
中
这篇关于iOS 类的数据结构的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2022-10-05Swift语法学习--基于协议进行网络请求
- 2022-08-17Apple开发_Swift语言地标注释
- 2022-07-24Swift 初见
- 2022-05-22SwiftUI App 支持多语种 All In One
- 2022-05-10SwiftUI 组件参数简写 All In One
- 2022-04-14SwiftUI 学习笔记
- 2022-02-23Swift 文件夹和文件操作
- 2022-02-17Swift中使用KVO
- 2022-02-08Swift 汇编 String array
- 2022-01-30SwiftUI3.0页面反向传值