runtime的理解

runtime 运行时机制(详情)

1 是什么?

runtime是一套比较底层的C语言API,属于一个C语言库,包含了很多底层的C语言API
平时编写的OC代码,在程序运行过程中,其实都是转成了runtime的C语言代码,runtime算是OC的幕后工作者

2 相关的头文件和函数

头文件:

1
2
<objc/runtime.h>
<objc/message.h>

3 特性

  • 可以动态地创建类
  • 动态的添加变量和属性,动态地遍历变量和属性
  • 动态地添加方法,转化方法

4相关应用

methodSwizzling

比如公司项目后期突然提出新的需求要为所有页面添加统计功能,也就是用户进入这个页面就统计一次,

实现:给UIViewController写一个类别加到pch
类别中新建一个swillingViewDidLoad方法
在实现中,+(load)中运用runtime的method_exchangeImplementations替换掉系统的viewDidload方法和swillingViewDidLoad方法;
在swillingViewDidLoad方法中加入统计方法,然后调用swillingViewDidLoad方法
这样,当controller调用viewDidload时通过运行时,指向了自定义的swillingViewDidLoad,在这个方法里先执行了我们的统计方法,然后调用swillingViewDidload方法,指向系统的viewDidload方法,这样就实现了在每个类viewDidload前进行统计的操作。
还有数组越界,给系统的NSArray 替换一个自定义objectAtIndex

动态地给Category 添加属性详情

分类里面不能添加Ivar是因为分类本身并不是一个真正的类,它并没有自己的ISA。有兴趣可以研究一下类是怎么被创建出来的,类最开始生成了很多基本属性,比如IvarList,MethodList,分类只会将自己的method attach到主类,并不会影响到主类的IvarList。这就是为什么分类里面不能增加成员变量的原因。

runtime中的category

1
2
3
4
5
6
7
struct objc_category {
char *category_name OBJC2_UNAVAILABLE;
char *class_name OBJC2_UNAVAILABLE;
struct objc_method_list *instance_methods OBJC2_UNAVAILABLE;
struct objc_method_list *class_methods OBJC2_UNAVAILABLE;
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;
}

所有的关联对象都由AssociationsManager管理,而AssociationsManager定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
class AssociationsManager {
static OSSpinLock _lock;
static AssociationsHashMap *_map; // associative references: object pointer -> PtrPtrHashMap.
public:
AssociationsManager() { OSSpinLockLock(&_lock); }
~AssociationsManager() { OSSpinLockUnlock(&_lock); }
AssociationsHashMap &associations() {
if (_map == NULL)
_map = new AssociationsHashMap();
return *_map;
}
};

AssociationsManager里面是由一个静态AssociationsHashMap来存储所有的关联对象的。这相当于把所有对象的关联对象都存在一个全局map里面。而map的的key是这个对象的指针地址(任意两个不同对象的指针地址一定是不同的),而这个map的value又是另外一个AssociationsHashMap,里面保存了关联对象的kv对。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void *objc_destructInstance(id obj)
{
if (obj) {
Class isa_gen = _object_getClass(obj);
class_t *isa = newcls(isa_gen);
// Read all of the flags at once for performance.
bool cxx = hasCxxStructors(isa);
bool assoc = !UseGC & _class_instancesHaveAssociatedObjects(isa_gen);
// This order is important.
if (cxx) object_cxxDestruct(obj);
if (assoc) _object_remove_assocations(obj);
if (!UseGC) objc_clear_deallocating(obj);
}
return obj;
}

runtime的销毁对象函数objc_destructInstance里面会判断这个对象有没有关联对象,如果有,会调用_object_remove_assocations做关联对象的清理工作。

NSCoding详情

归档和解档,利用runtime遍历模型对象的所有属性,写成宏文件

字典 –> 模型

利用runtime遍历模型对象的所有属性,根据属性名从字典中取出对应的值,设置到模型的属性上

KVO(原理)详情介绍

利用runtime动态产生一个类

消息转发

当我们像一个对象发送消息[Receiver message],Receiver没有实现该消息,即[Receiver respondsToSelector:SEL]返回为NO情况下,其实系统不会立刻出现crash,这时Runtime system会对message进行转发。转发之后,如果该消息依然没有被执行就会出现Crash!Runtime System为我们提供了三种解决这种给对象发送没有实现消息方案。

  1. 动态方法解析+ (BOOL)resolveInstanceMethod:(SEL)sel
  2. 备用接收者 - (id)forwardingTargetForSelector:(SEL)aSelector
  3. 完整转发 - (void)forwardInvocation:(NSInvocation *)anInvocation

API HOOK技术

用于封装框架(想怎么改就怎么改)

万能界面跳转

相关函数

  • objc_msgSend :给对象发送消息
  • class_copyMethodList: 遍历某个类所有的方法
  • class_copyIvarList: 遍历某个类所有的成员变量