什么是Runtime(运行时)
Runtime是用来将面向对象的Objective-C转换成面向过程的C的一套纯C语言API,有了Runtime可以将数据类型的确定由编译时推迟到运行时。
在Runtime中类和对象如何表示
在runtime中,Objective-C的类是由Class类型来表示的。在objc.h中可以看到Class类型实际上是指向结构体objc_class的指针。在这个结构体中有几个重要的字段:
isa:在Objective-C中所有的类自身也是一个对象。对象需要isa指针来找到它的类,类需要isa指针来找到它的元类。任何NSObject继承下的元类都有isa指针指向它的元类,而NSObject的isa指针指向NSObject元类。
super_class:指向该类的父类,如果该类是最顶层的类,super_class为nil
cache:用来缓存类中最近使用的方法
ivars:指向该类成员变量链表
methodLists:指向方法定义的链表
protocols:指向协议链表
如何使用Runtime动态添加一个类
使用runtime动态创建一个类或对象需要用到三个函数:
objc_allocateClassPair(<#Class _Nullable __unsafe_unretained superclass#>, <#const char * _Nonnull name#>, <#size_t extraBytes#>):创建一个新类或者元类。要想使其成为基类必须将super_class置为nil。参数extraBytes是分配给类和元类对象尾部索引ivars的字节数,通常为0
objc_registerClassPair(<#Class _Nonnull __unsafe_unretained cls#>):创建完新类后需要使用这个函数来注册这个类,之后才能在程序中使用。
objc_disposeClassPair(<#Class _Nonnull __unsafe_unretained cls#>):用来销毁该类及其元类,在销毁之前需要将该类的实例全部置为nil。
如何使用Runtime在类别(Category)中添加属性
runtime提供关联对象方法,动态地为添加到Category的属性实现getter和setter。
objc_setAssociatedObject(<#id _Nonnull object#>, <#const void * _Nonnull key#>, <#id _Nullable value#>, <#objc_AssociationPolicy policy#>):用来实现setter
objc_getAssociatedObject(<#id _Nonnull object#>, <#const void * _Nonnull key#>):用来实现getter
事实上,关联对象是使用哈希表实现的,将一个类映射到一张哈希表上,然后根据key找到关联对象。
Runtime和消息传递机制
消息传递用到的函数是objc_msgSend( id self, SEL op, ... )。参数self代表消息接受者,SEL表示方法名。每个类的方法列表(methodLists)中的指针都会指向方法的实现,方法名是查询时用到的key。消息传递流程如下:
objc_msgSend通过isa指针找到接受者所属的类
在该类的cache和methodLists中通过SEL查找对应的方法,找到就跳转至实现代码IMP
如果找不到就通过super_class到该类的父类中找
如果都找不到就执行消息转发机制
Runtime和消息转发机制
1、动态补加方法(动态方法解析)
+ (BOOL)resolveInstanceMethod:(SEL)sel
+ (BOOL)resolveClassMethod:(SEL)sel
这两个方法的参数就是未知的方法,返回的是BOOL类型,表示这个类能否动态的添加一个新的方法来处理这条信息。
2、直接返回消息给另一个对象处理(备用接收者)
- (id)forwardingTargetForSelector:(SEL)aSelector
3、手动生成签名方法并抓发给另一个对象(完整的消息转发机制)
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sSelector
- (void)forwardInvocation:(NSInvocation *)anInvocation
Runtime和KVC:暴力访问私有属性和变量
KVC访问变量不受私有权限的限制。runtime可以使用class_copyIvarList函数获取类对象的Ivar变量列表,可以使用object_getIvar和object_setIvar对变量进行暴力访问。
Runtime暴力访问对象私有方法
使用class_copyMethodList来获取类对象的方法列表,使用performSelector执行某个方法。还可以使用class_addMethod往类对象中强行添加新的方法。
网友评论