RunTime 基础数据结构
2021-01-19 本文已影响0人
某非著名程序员
1.源码
RunTime源码阅读(一)之weak
RunTime源码阅读(二)关联对象
RunTime源码阅读(三)dealloc的释放
RunTime源码阅读(四)内存管理
RunTime源码阅读(五)之category原理
RunTime源码阅读(六)之消息查找
RunTime源码阅读(七)之load加载原理
RunTime源码阅读(八)之autoreleasepool
RunTime源码阅读(九)之isa指针,类,元类
RunTime源码阅读(十)之方法交换原理
RunTime源码阅读(十一)之方法添加原理
iOS 实例方法和类方法中的self与self.class有什么区别?
iOS 多个category同时交换同一个方法
2.基本数据结构
2.1objc_object
id = objc_object:isa_t
- isa_t
- 关于isa操作相关
- 弱引用
- 关联对象
- 内存管理
2.2objc_class
class=objc_class继承自objc_object
- Class superClass
- cache_t cache
- class_data_bits_t bits
2.3isa指针
- 共用体isa_t
- 指针型isa:值代表Class的地址
- 非指针型isa:部分代表Class的地址
- isa指向
实例对象的isa指向类对象,类对象的isa指向元类
2.4cache_t
- 用于快速查找方法执行函数
- 是可增量扩展的哈希表结构
- 是局部性原理的最佳应用
cache_t是一个数组,数组元素是bucket_t(key IMP)
2.5class_data_bits_t
- 主要是对class_rw_t的封装
- class_rw_t代表了类相关的读写信息、对class_ro_t的封装
-
class_ro_t代表了类相关的只读信息
class_rw_t.png
2.6class_ro_t
class_ro_t.png2.7 method_t
method_t.pngType Encoding.png
2.8整体数据结构
整体数据结构.png3.实例对象、类对象、元类对象
- 类对象:存储实例方法等列表信息
元类对象:存储类对象的实例方法等列表信息 - 区别
实例对象通过 isa 指针找到类对象,类对象通过 isa 指针找到元类对象。
类对象和元类对象都是 objc_class 结构,继承自 objc_object。才有 isa 指针,才能实现。
- NSStringFromClass([self class]));
NSStringFromClass([super class]);
输出的结果是什么?为什么?
[self class]->objc_msgSend(self,@selector(class))
[super class]->objc_msgSendSuper(super,@select(class))
struct objc_super结构体中id receiver;指向当前实例对象的
4.消息传递
- cache_getImp缓存查找,汇编实现
- getMethodNoSuper_nolock:当前类查找
- 根据IsFixedUp区分是否已经排序,已经排序的用二分查找,否则用一般遍历查找
- 父类查找:superclass逐级父类查找
- _class_resolveMethod根据是否是元类,进行添加实例方法还是类方法
5.方法缓存
采用哈希查找:利用cache_key_t找到对应的bucket_t
key:sel value:bucket_t中的imp
6.消息转发、动态添加方法
消息转发.png- _class_resolveMethod动态添加方法
- 添加实例方法
resolveInstanceMethod-class_getInstanceMethod-class_addMethod - 添加类方法
resolveClassMethod-class_getClassMethod-class_addMethod
- 快速消息转发 forwardingTargetForSelector:
给其他对象执行 - 标准消息转发
方法签名:methodSignatureForSelector
处理方法前面:forwardInvocation
doesNotRecognizeSelector
7.Method-Swizzling
- 方法交换:分类中对同一个方法进行交换会发生什么?
- AOP切面编程:直接交换的风险
多线程交换不安全、方法交换名冲突 - 不侵入业务代码:如方法耗时统计,统计业务时长
- 为系统方法添加扩展功能
8.动态方法解析
@dynamic
- 动态运行时语言将函数决议推迟到运行时。
setter、getter在调用时动态生成。赖加载 - 编译时语言在编译期进行函数决议
- 编译后是无法修改方法。