介绍消息转发的机制
消息转发的条件
- 如何创建demo: OC 头文件中有方法名称,没有方法实现的时候会触发消息转发机制;
- 从子类 isa 的 methodlist 中开始找方法实现,一直找到 rootClass, 如果没有找到则触发消息转发机制;
消息转发类型
- 动态转发
// 动态转发(添加一个方法实现)
+ (BOOL)resolveInstanceMethod:(SEL)sel
- 快速转发
// 快速转发(创建一个备用接受者)
- (id)forwardingTargetForSelector:(SEL)aSelector
- 慢速转发
// 慢速转发 (创建方法签名,调用下面一个方法)
// 1.方法签名;2.消息转发;两个方法配合使用
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
- (void)forwardInvocation:(NSInvocation *)anInvocation
动态转发
为方法添加一个实现
v@:@
v
返回值是 void;
@
方法名称是一个object
:
第一个参数标识
@
第一个参数是一个object
+ (BOOL)resolveInstanceMethod:(SEL)sel {
NSLog(@"%s", __func__);
// 1. 匹配方法;
NSString *methodName = NSStringFromSelector(sel);
if ([methodName isEqualToString:@"sendMessage:"]) {
return class_addMethod(self, sel, (IMP)sendMessage, "v@:@");
}
return NO;
}
void sendMessage(id self, SEL _cmd, NSString* msg) {
NSLog(@"---%@", msg);
}
快速转发
为方法创建一个备用接受者
// 快速转发(创建一个备用接受者)
- (id)forwardingTargetForSelector:(SEL)aSelector {
NSLog(@"%s", __func__);
NSString *methodName = NSStringFromSelector(aSelector);
if ([methodName isEqualToString:@"sendMessage:"]) {
return [SpareWheel new];
}
return [super forwardingTargetForSelector:aSelector];
}
慢速转发
为方法添加一个签名
获取方法编号,并给方法找一个处理者
// 慢速转发 (创建方法签名,调用下面一个方法)
// 1.方法签名;2.消息转发;
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
NSLog(@"%s", __func__);
NSString *methodName = NSStringFromSelector(aSelector);
if ([methodName isEqualToString:@"sendMessage:"]) {
return [NSMethodSignature signatureWithObjCTypes:"v@:@"];
}
return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation {
SEL sel = [anInvocation selector];
SpareWheel *tempObj = [SpareWheel new];
if ([tempObj respondsToSelector:sel]) {
[anInvocation invokeWithTarget:tempObj];
}
[super forwardInvocation:anInvocation];
}
慢速转发以后防止崩溃
// 为应用崩溃做过什么事情, 加强 app 的健壮性
- (void)doesNotRecognizeSelector:(SEL)aSelector {
NSLog(@"找不动方法");
}
相关代码
需要引如头文件
#import <objc/runtime.h> #import <objc/message.h>
- 测试代码
1、导入头文件<objc/message.h>
2、设置enable strict checking of obc_msgSend calls为NO(否则objc_msgSend的参数会报错)
objc_msgSend([Person new], @selector(sendMessage:), @"helloMessage");
- 相关代码
@implementation Person
// 动态转发(添加一个方法实现)
+ (BOOL)resolveInstanceMethod:(SEL)sel {
NSLog(@"%s", __func__);
// 1. 匹配方法;
NSString *methodName = NSStringFromSelector(sel);
if ([methodName isEqualToString:@"sendMessage:"]) {
return class_addMethod(self, sel, (IMP)sendMessage, "v@:@");
}
return NO;
}
// 快速转发(创建一个备用接受者)
- (id)forwardingTargetForSelector:(SEL)aSelector {
NSLog(@"%s", __func__);
NSString *methodName = NSStringFromSelector(aSelector);
if ([methodName isEqualToString:@"sendMessage:"]) {
return [SpareWheel new];
}
return [super forwardingTargetForSelector:aSelector];
}
// 慢速转发 (创建方法签名,调用下面一个方法)
// 1.方法签名;2.消息转发;
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
NSLog(@"%s", __func__);
NSString *methodName = NSStringFromSelector(aSelector);
if ([methodName isEqualToString:@"sendMessage:"]) {
return [NSMethodSignature signatureWithObjCTypes:"v@:@"];
}
return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation {
SEL sel = [anInvocation selector];
SpareWheel *tempObj = [SpareWheel new];
if ([tempObj respondsToSelector:sel]) {
[anInvocation invokeWithTarget:tempObj];
}
[super forwardInvocation:anInvocation];
}
// 为应用崩溃做过什么事情, 加强 app 的健壮性
- (void)doesNotRecognizeSelector:(SEL)aSelector {
NSLog(@"找不动方法");
}
void sendMessage(id self, SEL _cmd, NSString* msg) {
NSLog(@"---%@", msg);
}
//-(void)sendMessage:(NSString *)nickname {
// NSLog(@"%s-%@", __func__, nickname);
//}
@end
@implementation SpareWheel
-(void)sendMessage:(NSString *)nickname {
NSLog(@"%s-%@", __func__, nickname);
}
@end
面试相关问题
- 消息转发机制?
从子类的 isa 中 的 methodlist 获取实现方法,一直向上,直到rootclass;
如果没有找到实现方法,则进入消息转发机制; - 消息转发过程?
动态转发(创建实现),快速转发(创建备用接受类),慢速转发(创建签名,并找一个处理者) - 为app崩溃做过一些什么事情,加强app 的健壮性?
- (void)doesNotRecognizeSelector:(SEL)aSelector