runtime简介
runtime,也就是运行时, 即在运行的时候的一些机制。Objective-C采用的就是运行时机制。与之相反的就是 C语言。对于C来说,函数的调用在编译的时候就会决定。对于Objective-C,函数回采用动态调用的过程,在编译的时候不确定会调用哪个函数,而是在运行的时候才会根据函数的名称找到对应的函数来执行调用。
比如:
一个函数声明但没有实现,C语言在编译的时候就会报错,而Objective-C在编译的时候不会报错,而是运行的时候报错。
发送消息
任何方法的调用都是发送消息。
前面说到,Objective-C采用运行时机制,其中最主要的就是消息机制。那么如何发送消息呢?
就用最常用的声明一个类对象来说:
NSObject *obj = [[NSObject alloc]init];
我们将它分解为:
NSObject *obj = [NSObject alloc];
obj = [obj init];
这里我们调用了+alloc
和 -init
两个方法,这两个方法在终端使用clang -rewrite-objc
可以看到编译器将上面两行代码转化为如下形式:
NSObject *obj = ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("alloc"));
obj = ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)obj, sel_registerName("init"));
去掉所有的强制类型转换:
NSObject *obj = objc_msgSend(objc_getClass("NSObject"), sel_registerName("alloc"));
obj = objc_msgSend(obj, sel_registerName("init"));
可以看出,其实它一直在调用objc_msgSend
这个函数。我们可以看看这个函数的定义:
/**
* Sends a message with a simple return value to an instance of a class.
* @param self A pointer to the instance of the class that is to receive the message.
* @param op The selector of the method that handles the message.
* @param ...
* A variable argument list containing the arguments to the method.
* @return The return value of the method.
*/
id objc_msgSend(id self, SEL op, ...)
可以了解:
-
objc_msgSend
就是发送消息的函数; - 第一个参数是方法的接收方;
- 第二个参数是携带消息的方法;
-
...
表示可变参数,用来表示方法中的参数; - 返回值就是方法的返回值,即执行第二个参数方法的结果。
也就是说,我们只要按照上述规则传入对应的值即可发送消息。
我们做一个试验:
定义一个 RuntimeTest类:
@interface RuntimeTest : NSObject
// 无参数的方法
- (void)func1;
// 带一个参数的方法
- (void)func2WithParam:(NSInteger)param;
// 带两个参数的方法
- (void)func3WithParam1:(NSInteger)param1 param2:(NSInteger)param2;
@end
@implementation RuntimeTest
- (void)func1{
NSLog(@"%s", __func__);
}
- (void)func2WithParam:(NSInteger)param{
NSLog(@"%s", __func__);
NSLog(@"param ---> %ld", param);
}
- (void)func3WithParam1:(NSInteger)param1 param2:(NSInteger)param2{
NSLog(@"%s", __func__);
NSLog(@"param1 ---> %ld", param1);
NSLog(@"param2 ---> %ld", param2);
}
@end
利用runtime声明并调用它的方法:
RuntimeTest *test = objc_msgSend([RuntimeTest class], @selector(alloc));
test = objc_msgSend(test, @selector(init));
objc_msgSend(test, @selector(func1));
objc_msgSend(test, @selector(func2WithParam:), 1);
objc_msgSend(test, @selector(func3WithParam1:param2:), 2, 3);
运行结果:
-[RuntimeTest func1]
-[RuntimeTest func2WithParam:]
param ---> 1
-[RuntimeTest func3WithParam1:param2:]
param1 ---> 2
param2 ---> 3