先上图:
下面根据具体代码看这张图。
一、创建一个Person类,
Person.h
#import <Foundation/Foundation.h>@interface Person : NSObject-(void)sendMessage:(NSString *)message;@end
Person.m
#import "Person.h" #import <objc/runtime.h>@implementation Person@end
大家可以看到,Person类只声明了 sendMessage:方法,在.m文件里没有实现这个方法。
这时,如果在viewController中调用Person类的sendMessage方法,程序会发生崩溃。
#import "ViewController.h" #import "Person.h"@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];[[[Person alloc]init] sendMessage:@"Hello"];}
结合上面的图片,我们说说消息处理的机制。
1.当我们调用的方法没有具体的实现时,会调用
+ (BOOL)resolveInstanceMethod:(SEL)sel;
+(BOOL)resolveInstanceMethod:(SEL)sel{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 *message){NSLog(@"message=%@",message); }
BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types):为类动态添加方法。如果有同名会返回NO,成功返回YES。
其中的参数types查询地址:(v:表示void, @:表示类型,等等)
2. 如果 resolveInstanceMethod:方法返回NO,调用
-(id)forwardingTargetForSelector:(SEL)aSelector;
这个方法是找备用者,比如:Animal类。
Animal.h
#import <Foundation/Foundation.h>@interface Animal : NSObject@end
Animal.m
#import "Animal.h"@implementation Animal-(void)sendMessage:(NSString *)message{NSLog(@"message=%@",message); }@end
Animal类没有声明sendMessage:方法,但在.m文件里有这个方法的实现,可以作为备用者。如下:
-(id)forwardingTargetForSelector:(SEL)aSelector{NSString *methodName = NSStringFromSelector(aSelector);if ([methodName isEqualToString:@"sendMessage:"]) {if ([[Animal new] respondsToSelector:aSelector]) {return [Animal new];}}return [super forwardingTargetForSelector:aSelector]; }
3. 如果 forwardingTargetForSelector:(SEL)aSelector返回 nil。
// 若前两种方法都不处理,则走这里 // 1)方法签名 -(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{NSString *methodName = NSStringFromSelector(aSelector);if ([methodName isEqualToString:@"sendMessage:"]) {return [NSMethodSignature signatureWithObjCTypes:"v@:@"];}return [super methodSignatureForSelector:aSelector]; } // 2) 签名后,消息转发,找备用者 -(void)forwardInvocation:(NSInvocation *)anInvocation{SEL selector = [anInvocation selector];Animal *animal = [Animal new];if ([animal respondsToSelector:selector]) {[anInvocation invokeWithTarget:animal];} else{[super forwardInvocation:anInvocation];} }
4.如果走到第3步,仍然不做处理,如下:
-(void)forwardInvocation:(NSInvocation *)anInvocation{[super forwardInvocation:anInvocation]; }
这时为了程序的健壮性,防止崩溃,可以用以下方法处理。
// 若前3方法都不处理,为了防止崩溃,可调用此方法 -(void)doesNotRecognizeSelector:(SEL)aSelector{NSString *methodName = NSStringFromSelector(aSelector);NSLog(@"找不到 %@ 这个方法的实现",methodName); }
附加源码