先上图:
下面根据具体代码看这张图。
一、创建一个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);
}