objc runtime (一)发送消息

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

你可能感兴趣的:(objc runtime (一)发送消息)