什么是消息转发?其实OC的方法调用就是消息转发的过程,比如创建一个名为Persion的类,调用alloc和init方法,其实就是给系统发送了“alloc”和“init”消息,代码如下:
// alloc :分配内存空间 malloc()用来分配内存的,告诉系统,给我一块空间
// init :初始化对象,属性&方法
Persion *p = [[Persion alloc] init];
接下来我们就具体看一下他是怎么发送消息的
首先我们的导入头文件#import
平时我们调OC的方法是这样,比如先在perison类里实现一个方法,然后在外边调用一下
#import "Persion.h"
@implementation Persion
-(void)sleep {
NSLog(@"睡了!!!");
}
@end
Persion *p = [[Persion alloc] init];
[p sleep];
2018-05-25 14:59:13.229804+0800 消息转发机制[11297:262465] 睡了!!!
然后我们点进
objc_msgSend(id _Nullable self, SEL _Nonnull op, ...)
没错这个就是用来发送消息的方法,从提示可以大致看出需要传什么参数了,接下来就用它替换一下上边的代码,像这样:
Persion *p = objc_msgSend([Persion class], @selector(alloc));
p = objc_msgSend(p, @selector(init));
[p sleep];
2018-05-25 15:51:23.654009+0800 消息转发机制[11939:332368] 睡了!!!
试试开始明白点什么了,嘿嘿!
上边的代码中还是有一些OC的代码,我们还能用C语言的函数来替换一下:
Persion *p = objc_msgSend(objc_getClass("Persion"), sel_registerName("alloc"));
p = objc_msgSend(p, sel_registerName("init"));
[p sleep];
2018-05-25 15:55:47.188866+0800 消息转发机制[12018:338981] 睡了!!!
其实在.m文件编译后,我们的alloc和init方法就被编译成了上边的C语言代码。
还有就是我们看objc_msgSend(id _Nullable self, SEL _Nonnull op, ...),参数最后又三个点,说明它是可扩展,那我们就试着传个参数试试,首先把Persion的方法改下:
-(void)sleepWithTime:(NSString *)time {
NSLog(@"睡了%@!!!",time);
}
Persion *p = objc_msgSend(objc_getClass("Persion"), sel_registerName("alloc"));
p = objc_msgSend(p, sel_registerName("init"));
objc_msgSend(p, sel_registerName("sleepWithTime:"), @"3小时");
2018-05-25 16:17:55.577908+0800 消息转发机制[12294:365274] 睡了3小时!!!
完美!!!
到这里在给大家介绍一个方法,objc_msgSendSuper(<#struct objc_super * _Nonnull super#>, <#SEL _Nonnull op, ...#>)
,从方法名可以看出,它就是给父类发消息的方法了,首先创建一个Persion的子类,oldPersion,然后实现父类的方法
-(void)sleepWithTime:(NSString *)time {
NSLog(@"子类的方法");
}
objc_msgSendSuper从提示可以看出第一个参数是个父类的结构体,点进去看
两个参数:
- receiver:一个实例,也就是我们oldPersion的实例
- super_class父类的类型
于是我们先创建一个结构体,然后把它的地址作为objc_msgSendSuper的第一个参数。
然后第二步就是给父类发消息了,像这样
oldPersion *p = [[oldPersion alloc] init];
struct objc_super oldSuper = {p ,class_getSuperclass(objc_getClass("oldPersion"))};
objc_msgSendSuper(&oldSuper, sel_registerName("sleepWithTime:"), @"8小时");
2018-06-28 10:46:58.155 消息转发机制[232:7780] 睡了8小时!!!
最后oldPersion跳过自己的方法,调用了父类的方法。