Runtime看这一篇就够了

一、概念、常见应用、使用方式

1.1概念:(关键字:C的API 源C/C++/汇编 动建类/对象 消息传递/转发 类结构体 方法C函数 调的方法objc_msgSend 封装)

Runtime顾名思义,运行时,是一套C语言的API,底层源码是C/C++/汇编。

OC是一门动态性较强的编程语言,即允许很多操作推迟到程序运行时再运行,故需要运行时系统动态创建类和对象、进行消息传递和转发。

OC的动态性就是由Runtime来支撑和实现的,OC代码底层都是转换成RuntimeAPI调用,比如类转成runtime库里的结构体等数据类型,方法转成C语言函数,调的方法转成了objc_msgSend函数。Runtime库里包含跟类、成员变量、方法相关的API,封装了很多和动态性相关的函数。

1.2常见应用:(关键字:关加属 遍all员 动建员 动加法 换法 法异消转)

用关联对象给分类添加属性、遍历所有类的成员变量(比如文本框占位文字的颜色、字典转模型、自动解归档)、为类动态添加成员变量、为类动态添加新的方法、交换方法实现、方法找不到的异常用消息转发机制解决。

1.3使用方式:(关键字:运时为分类绑属性 影响全app)

禁多点:.m动绑属监点击 略重复点 .m类型assign控制是否能点 限时只响应1次

导入<objc/message.h>,<objc/runtime.h>

category只能新增方法,不能为直接原有类添加属性;但通过runtime.h运行时来为分类绑定属性,正常绑定get/set方法。

注意:新增的属性会对整个程序产生影响,而不是导入头文件才有效。

利用runtime的selector禁止点击事件多次触发 具体为UIControl或UIButton创建分类。

在.m文件#import<objc/runtime.h>使用runtime动态绑定属性监听点击事件,忽略重复点击,设置.h中定义的assign类型控制是否能点击属性eventTimeInterval,使其在规定时间内只响应一次点击事件。

分类的load(所有NS子类都有的运时载的类方法 执早 不需手调 唯一 无抢资源问题)方法中加method swizzling和替法 )

先添加一个category,然后在category中的+(void)load中添加method swizzling方法 ,用来替换的方法也写在category中,

+(void)load方法:所有NSObject子类都具备的用于运行时加载处理的一个类方法,执行比较早且不需要手动调用,且该方法具有唯一性,不用担心资源抢夺的问题。C语言的API

二、数据结构

objc_object objc_class cache_t class_rw_t class_ro_t method_t TypeEncoding

2.1id=objc_object isa_t isa相关操作 (获取isa指向的类对象 通过isa指针获取元类对象) 弱引用(相关方法如标记对象 指针) 关联对象 内存管理 相关的方法实现retain release @atuoreleasepool

2.2Class=objc_class结构体 类对象 (继承自objc_object)Class包含Class superClass; cache_t cache;方法缓存 class_data_bits_t bits;类定义的属性、变量、方法都在里面

2.2.1方法缓存cache_t (关键字:快查 增扩的哈希表 缓存曾调法 局原理)

快速查找方法执行函数、用可增量扩展的哈希表/散列表结构 缓存曾调用过的方法 局部性原理的最佳应用

cache_t存储了散列表bucket_t的数组,散列表长度,已缓存方法数量;bucket_t含key和IMP(IMP无类型的函数指针)

2.2.2

class_data_bits_t是对class_rw_t的封装,class_rw_t是对class_ro_t的封装

class_rw_t 里面的方法、协议、属性是二维数组,包含类和分类的初始内容

class_ro_t里面的base方法methodList(里面是多个method_t)、协议、属性、const ivars是一维数组,是只读的,包含类的初始内容

method_t是对方法和函数的封装 struct method_t{

SEL name;//函数名

const char *types;//编码(返回值类型、参数类型)

IMP imp;//指向函数的指针(函数地址)}

SEL方法\函数名,一般叫选择器,底层结构与char*类似;

不同类同名方法,所对应的方法选择器是相同的typedef struct object_selector *SEL;

SEL可通过@selector()和sel_registerName()获得;可通过sel_getName()和NSStringFromSelector()转成字符串

IMP代表函数的具体实现 typedef id _Nullable(*IMP)(id _Nonnull,SEL _Nonnull,……);

Type Encoding

iOS中提供@encode的指令,可将具体的类型表示成字符串编码

2.3 isa指针

指针型isa和非指针型isa 值部分代表class的地址 实例对象--isa指向-->类对象class--isa指向-->元类对象metaClass

在arm64架构前,isa是存类和元类对象的内存地址的普通指针;之后优化后的isa变成共用体union结构,用位域存储更多信息

union isa_t

{ Class cls;

uintptr_t bits;

struct{

uintptr_t nonopointer 0普通指针,存类和元类对象的内存地址 1

uintptr_t has_assoc是否设置过关联对象

uintptr_t has_cxx_dtor是否有C++析构函数 weakly_referenced是否被弱引用指向过 若没有释放得更快

uintptr_t deallocating对象是否正在释放

uintptr_t has_sidetable_rc引用计数器是否过大无法存在isa中 若为1引用计数存储在SideTable类的属性中

uintptr_t extra_rc里面存储的值是引用计数减1

uintptr_t shiftcls 存储着类、元类对象的内存地址的信息 magic 用于在调试时分辨对象是否未完成初始化

uintptr_t method_t对方法/函数的封装

三、类与元类对象、消息传递机制

3.1类与元类对象存储、指向

类对象存 实例 方法列表等信息。根类指向nil。继承自objc_Object,所以有isa指针,通过isa指针找到元类对象,从而访问关于类方法列表相关信息

元类对象存 类 方法列表等信息。根元类对象的superclass指针指向根类对象。

3.1.2如果调用的类方法,没有对应实现,但有同名实例方法实现,会不会发生崩溃,会不会产生实际调用?

调用类方法,从元类方法列表查找,沿着红色箭头逐级父类查找,当在元类方法列表中找不到,就会到根类对象找 同名的实例方法实现

3.2消息传递过程

比如调用实例方法A,系统根据当前实例的isa指针找到类对象,在类对象中遍历方法列表,查找同名的方法实现,如果没有查找到会顺次以superclass的指向查找父类类对象方法列表,查找根类类对象方法列表,一直向上查找,如果没有查找到,就会走到消息转发流程。

比如调用类方法B,通过类对象的isa指针找到元类对象,顺次遍历方法列表,直到根元类对象,再到根类对象,再到nil

父类,子类,给定实例id类型 isa成员变量,指向实例对应的类对象,classA创建出instanceA,isa指针指向classA,子类的父类也有一个实例

3.2.1消息传递过程中的方法查找

当前类、父类中查找

当前类中查找:对于已排序好的列表,二分查找方法对应执行函数;没排序的,一般遍历。

四、动态方法解析/ 添加、消息转发、Method-Swizzling

objc_magSend 消息传递 receiver isa receiverClass superclass superClass cache class_rw_t  已二分查找 无遍历查找

动态方法解析 +resolveInstanceMethod: +resolveClassMethod

消息转发机制

五、super的本质

super调用,底层会转换为objc_msgSendSuper2函数的调用,接收2个参数 struct objc_super2 和SEL

struct objc_super2里有2个参数 struct objc_super2{ id receiver;//消息接收者

Class current_class;//receiver的Class对象 };

六、LLVM的中间代码IR

OC在变成机器代码前,会被LLVM编译器转换成中间代码Intermidiate Representation。可用命令行clang -emit -llvm -S main.m

语法简介:@ % alloca i32 align store load icmp br label call

@全局变量 %局部变量

alloca 在当前执行的函数堆栈帧中分配内存,当该函数返回到其调用者时,将自动释放内存

i32 32位字节的整数

align对齐 store写入 load读出 icmp两个整数值比较,返回布尔值 br选择分支 根据条件转向label不根据条件跳转类似goto label代码标签 call调用函数

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值