消息机制
7.png
- 上图我们可以看出iOS消息机制是分三步, 动态方法解析,消息转发重定向,生成方法签名以及方法的签名派发来实现,下面看具体demo
- Person (Person.m类没有实现方法)
#import <Foundation/Foundation.h>
@interface Person : NSObject
- (void)run;
@end
- Car类
#import <Foundation/Foundation.h>
@interface Car : NSObject
//- (void)carRun;
@end
#import "Car.h"
@implementation Car
- (void)run
{
NSLog(@"车=====:%@",@"跑起来了");
}
@end
- ViewController类
#import "ViewController.h"
#import "Person.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
Person *p = [Person new];
[p run];
}
@end
- 运行demo,[p run]没有实现引发崩溃 *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Person run]: unrecognized selector sent to instance 0x60400000f3a0',
*** First throw call stack:;
追踪下[p run]是崩溃的步骤
一.动态方法解析
+ BOOL)resolveClassMethod:(SEL)sel OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
+ (BOOL)resolveInstanceMethod:(SEL)sel OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
二.消息转发重定向
- (id)forwardingTargetForSelector:(SEL)aSelector OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
三.生成方法签名
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector OBJC_SWIFT_UNAVAILABLE("");
四.方法的签名派发
- (void)forwardInvocation:(NSInvocation *)anInvocation OBJC_SWIFT_UNAVAILABLE("");
- 上面一,二都能单独处理崩溃,三,四合在一起也是能处理,看看是如何用runtime来消息机制
- 动态方法解析来实现添加run方法
/**
动态方法解析
@param sel selector
@return yes or no
*/
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
//1.判断没实现方法, 就动态添加方法
if (sel == @selector(run)) {
// 动态添加方法 IMP(函数指针)
class_addMethod(self, sel, (IMP)runValue, "v@:");
return YES;
}
return [super resolveInstanceMethod:sel];
}
void runValue(id self , SEL sel)
{
//id self , SEL sel
}
- 动态方法解析返回NO的话就会走到消息重定向,我们把动态解析的动态添加方法给注释调让它返回NO
/**
动态方法解析
@param sel selector
@return yes or no
*/
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
// //1.判断没实现方法, 就动态添加方法
// if (sel == @selector(run)) {
// // 动态添加方法 IMP(函数指针)
// class_addMethod(self, sel, (IMP)runValue, "v@:");
// return YES;
// }
return [super resolveInstanceMethod:sel];
}
void runValue(id self , SEL sel)
{
//id self , SEL sel
}
//二.消息转发重定向
- (id)forwardingTargetForSelector:(SEL)aSelector OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0){
NSLog(@"aSelector ===== :%@",NSStringFromSelector(aSelector));
// return [Car new];
return [super forwardingTargetForSelector:aSelector];
}
- 注意这里的如果返回return [Car new];如果我们在Car 类方法里面找到 run这个方法,程序会崩溃么?找不到run方法的话又怎样呢?如果没找到的话,return [super forwardingTargetForSelector:aSelector];会怎样呢?
- 接下来看下生成的方法签名以及签名派发
//三.生成方法签名
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector OBJC_SWIFT_UNAVAILABLE("")
{
// return [super methodSignatureForSelector:aSelector];
NSString *selector = NSStringFromSelector(aSelector);
if ([selector isEqualToString:@"run"]){
NSLog(@"实现run方法");
}
//(const char *)types;
return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}
// 四.方法的签名配发
- (void)forwardInvocation:(NSInvocation *)anInvocation OBJC_SWIFT_UNAVAILABLE(""){
NSLog(@"----%@----",anInvocation);
//1.拿到消息
SEL selector = [anInvocation selector];
//转发消息
Car *car = [Car new];
if ([car respondsToSelector:selector]){
// 调用这个对象, 去进行转发
[anInvocation invokeWithTarget:car];
}
else {
/**
这里抛异常
*/
[super forwardInvocation:anInvocation];
}
}
- 控制台输出 8.png
- demo实例:https://github.com/defuliu/MessageMechanism.git
- 小福利 iOS注释快捷键 command +alt + / 能快速在方法体以及属性注释.
网友评论