美文网首页
NSInvocation的基本使用

NSInvocation的基本使用

作者: vincent_gao | 来源:发表于2018-02-11 13:11 被阅读0次

前提:

在 iOS中可以直接调用某个对象的消息方式有两种:
一种是performSelector:withObject;
再一种就是NSInvocation。
第一种方式比较简单,能完成简单的调用。但是对于>2个的参数或者有返回值的处理,那performSelector:withObject就显得有点有心无力了,那么在这种情况下,我们就可以使用NSInvocation来进行这些相对复杂的操作

NSInvocation的基本使用

-(void)viewDidLoad {
    [super viewDidLoad];
    [self invorkTest];
}
-(id)invorkTest{
    //方法
    SEL selector = @selector(run:content:);
    //初始化方法签名(方法的描述)
    NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:selector];
    
    //此时我们应该判断方法是否存在,如果不存在这抛出异常
    if (signature == nil) {
        //selector为传进来的方法
        NSString *info = [NSString stringWithFormat:@"%@方法找不到", NSStringFromSelector(selector)];
        [NSException raise:@"方法调用出现异常" format:info, nil];
    }
    
    // NSInvocation : 利用一个NSInvocation对象包装一次方法调用(方法调用者、方法名、方法参数、方法返回值)
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
    //设置调用者
    invocation.target = self;
    //设置调用方法
    invocation.selector = selector;
    //设置参数
    NSUInteger object = 5;
    //参数从2开始,index为0表示target,1为_cmd
    [invocation setArgument:&object atIndex:2];
    NSString*content =@"hello";
    [invocation setArgument:&content atIndex:3];
    //调用方法
    [invocation invoke];
    id res = nil;
    if (signature.methodReturnLength != 0) {//有返回值
        //将返回值赋值给res
        [invocation getReturnValue:&res];
    }
    return res;
 }
-(NSString*)run:(NSInteger)num content:(NSString*)content{
    NSString*ret =[NSString stringWithFormat:@"%@:%@",content,@(num)];
    NSLog(@"run:[num:%@,content:%@]",@(num),content);
    return ret;
}

NSInvocation实现多参数的封装

系统的NSObject提供的performSelector的方法只提供了最多两个参数的调用,我们可以使用NSInvocation封装一个多个参数的performSelector方法.

 #import <Foundation/Foundation.h>
 
 @interface NSObject (MutiPerform)
 
 -(id)performSelector:(SEL)Selector withObjects:(NSArray *)objects;
 @end
 #import "NSObject+MutiPerform.h"

@implementation NSObject (MutiPerform)

-(id)performSelector:(SEL)selector withObjects:(NSArray *)objects{
    
    //初始化方法签名
    NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:selector];
    
    // 如果方法selector不存在
    
    if(signature == nil){
        
        // 抛出异常
        NSString *reason = [NSString stringWithFormat:@"%@方法不存在",NSStringFromSelector(selector)];
        @throw [NSException exceptionWithName:@"error" reason:reason userInfo:nil];
    }
    
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
    
    invocation.target = self;
    invocation.selector = selector;
    
    //参数个数signature.numberOfArguments 默认有一个_cmd 一个target 所以要-2
    NSInteger paramsCount = signature.numberOfArguments - 2;
    
    // 当objects的个数多于函数的参数的时候,取前面的参数
    //当当objects的个数少于函数的参数的时候,不需要设置,默认为nil
    paramsCount = MIN(paramsCount, objects.count);
    
    for (NSInteger index = 0; index < paramsCount; index++) {
        
        id object = objects[index];
        
        // 对参数是nil的处理
        if([object isKindOfClass:[NSNull class]]) continue;
        
        [invocation setArgument:&object atIndex:index+2];
        
    }
    //调用方法
    [invocation invoke];
    
    // 获取返回值
    id returnValue = nil;
    
    //signature.methodReturnLength == 0 说明给方法没有返回值
    if (signature.methodReturnLength) {
        
        //获取返回值
        [invocation getReturnValue:&returnValue];
    }
    
    return returnValue;
}

相关文章

网友评论

      本文标题:NSInvocation的基本使用

      本文链接:https://www.haomeiwen.com/subject/lsvktftx.html