一、概念(什么是运行时)
运行时是苹果提供的纯C语言的开源库。
二、运行时的作用
1、能够获得某个类的所有成员变量
2、能够获得某个类的所有属性
3、能够获得某个类的所有方法
4、交换方法
5、动态创建一个类
5、能动态的添加一个成员变量
6、能动态的添加一个方法
三、案例
demo地址:github
1、获取某个类的所有成员变量
输出如下:
2、能够获得某个类的所有属性
上图中列出属性名,属性的类型为propertyAttributrs: T@"NSString",C,N,V_name
其中@表示property是OC类,"NSString"表明具体的OC类名,&:表明property为retain(strong),除此之外,C表示copy,assign没有表示。
N:表示nonatomic,若为atomic则不写。
V_name:V开头加property名
3.获得某个类的所有方法
4、交换方法
交换方法时注意,如果直接交换类方法是行不通的
Method是一个结构体,我们想要的IMP就在里面,看看结构
structobjc_method{
SELmethod_name OBJC2_UNAVAILABLE;
char*method_types OBJC2_UNAVAILABLE;
IMPmethod_imp OBJC2_UNAVAILABLE;
}
我们通过运行时的函数获取到了两个方法的IMP指针,之后在将他们互相交换(exchangeImplementations)。
这样在调用这两个方法时,由于找到方法的IMP指针已被替换,但是方法指针是需要指向实例化对象的,仅仅通过类名是行不通的。
5、动态创建类
6、能动态的添加一个成员变量和方法
四、底层实现
OC是一门动态语言,所以它总是想办法把一些决定工作从编译连接推迟到运行时。也就是说只有编译器是不够的,还需要一个运行时系统 (runtime system) 来执行编译后的代码。这就是 Objective-C Runtime 系统存在的意义,它是整个Objc运行框架的一块基石。
Messages
在Objective-C中,消息是通过objc_msgSend()这个runtime方法及相近的方法来实现的。这个方法需要一个target,selector,还有一些参数。理论上来说,编译器只是把消息分发变成objc_msgSend来执行。
[array insertObject:foo atIndex:5];
objc_msgSend(array,@selector(insertObject:atIndex:), foo,5);
Methods, Selectors and IMPs
class的方法列表其实是一个字典,key为selectors,IMPs为value。一个IMP是指向方法在内存中的实现。很重要的一点是,selector和IMP之间的关系是在运行时才决定的,而不是编译时。这样我们就能进行操作。
IMP通常是指向方法的指针,第一个参数是self,类型为id,第二个参数是_cmd,类型为SEL,余下的是方法的参数。这也是self和_cmd被定义的地方。下面演示了Method和IMP
- (id)doSomethingWithInt:(int)aInt{}
iddoSomethingWithInt(idself, SEL _cmd,intaInt){}