iOS开发之NSInvocation

一.概述

在iOS中我们直接调某个对象的消息的方式有2种

  • 系统NSObject类型中提供了2个方法

// 一个参数
[self performSelector:<#(SEL)#> withObject:<#(id)#>];
// 两个参数
[self performSelector:<#(SEL)#> withObject:<#(id)#> withObject:<#(id)#>];


- 使用NSInvocation.

### 二. NSInvocation的使用

```objc
- (void)viewDidLoad {
  [super viewDidLoad];

  //方法
  SEL selector = @selector(run);
  //初始化方法签名(方法的描述)   
   NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:selector];
  // 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];
  //调用方法
  [invocation invoke];

}
-(void)run:(NSInteger)num{


  NSLog(@"run");
}

三. NSInvocation实现多参数的封装

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

#import 

@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;
}


你可能感兴趣的:(iOS开发之NSInvocation)