先上图:

 

下面根据具体代码看这张图。

一、创建一个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);
}

 

附加源码

内容来源于网络如有侵权请私信删除
你还没有登录,请先登录注册
  • 还没有人评论,欢迎说说您的想法!