NSInvocation 的基本用法demo

在 iOS中可以直接调用某个对象的消息方式有两种:

一种是performSelector:withObject;

再一种就是NSInvocation。

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


NSInvocation的基本使用 demo

 @interface TestModel : NSObject
-(void)testMethod;

-(void)run:(NSArray  *)methodArr;

@end

@interface TestModel()
{
    TestModelHelper1 *  _testModelHelper1;
    NSInvocation     *  _invocation;
}
@end

@implementation TestModel
-(id)init
{
    if (self = [super init ])
    {

        _testModelHelper1 = [[TestModelHelper1 alloc]init];

       // 方法签名中保存了方法的名称/参数/返回值,协同NSInvocation来进行消息的转发
        // 方法签名一般是用来设置参数和获取返回值的, 和方法的调用没有太大的关系
        //1、根据方法来初始化NSMethodSignature
        NSMethodSignature  *signature = [TestModelHelper1 instanceMethodSignatureForSelector:@selector(run:method:)];

        //此时我们应该判断方法是否存在,如果不存在这抛出异常
        if (signature == nil)
        {
            //aSelector为传进来的方法
            NSString *info = [NSString stringWithFormat:@"%@方法找不到", NSStringFromSelector(@selector(run:))];
            [NSException raise:@"方法调用出现异常" format:info, nil];
            
        }
        else
        {

           2  根据方法签名来创建NSInvocation对象

           // NSInvocation中保存了方法所属的对象/方法名称/参数/返回值
            //其实NSInvocation就是将一个方法变成一个对象
            //创建NSInvocation对象
            _invocation = [NSInvocation invocationWithMethodSignature:signature];
            //设置方法调用者
            _invocation.target = _testModelHelper1 ;
            //注意:这里的方法名一定要与方法签名类中的方法一致
            _invocation.selector = @selector(run:method:);
            NSString *way = @"byCar";
            //这里的Index要从2开始,以为0跟1已经被占据了,分别是self(target),selector(_cmd)
           [_invocation setArgument:&way atIndex:2];
            //调用invoke方法
            [_invocation invoke];
            //判断当前调用的方法是否有返回值
            NSLog(@"type = %s",[signature methodReturnType]);
        }
    }
    return self;
}

-(void)run:(NSArray *)methodArr
{
    //此处不能通过遍历参数数组来设置参数,因为外界传进来的参数个数是不可控的
    //因此通过numberOfArguments方法获取的参数个数,是包含self和_cmd的,然后比较方法需要的参数和外界传进来的参数个数,并且取它们之间的最小值
    NSUInteger argsCount = _invocation.methodSignature.numberOfArguments - 2;
    NSUInteger arrCount = methodArr.count;
    NSUInteger count = MIN(argsCount, arrCount);
    for (int i = 0; i<count; i++)
    {
        id obj = methodArr[i];
        // 判断需要设置的参数是否是NSNull, 如果是就设置为nil
        if ([obj isKindOfClass:[NSNull class]]) {
            obj = nil;
        }
        [_invocation setArgument:&obj atIndex:i + 2];
    }

    //调用invoke方法
     [_invocation invoke];
}

@interface TestModelHelper1 : NSObject
-(void)testMethod;

-(NSString *)run:(NSString *)method method:(NSString *)method2;

@end

@implementation TestModelHelper1
-(void)testMethod
{
    NSLog(@"i am TestModelHelper1");
    _testValue =@"TestModelHelper1";
}
-(NSString *)run:(NSString *)method method:(NSString *)method2
{
    NSLog(@"run:%@-%@",method,method2);
    return _testValue;
}

@end


 调用:

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    TestModel * model = [[TestModel alloc]init];
    [model testMethod];
    [model run:@[@"test1",@"test2"]];
}

[signature methodReturnType] 类型有

enum _NSObjCValueType {
    NSObjCNoType = 0,
    NSObjCVoidType = 'v',
    NSObjCCharType = 'c',
    NSObjCShortType = 's',
    NSObjCLongType = 'l',
    NSObjCLonglongType = 'q',
    NSObjCFloatType = 'f',
    NSObjCDoubleType = 'd',
    NSObjCBoolType = 'B',
    NSObjCSelectorType = ':',
    NSObjCObjectType = '@',
    NSObjCStructType = '{',
    NSObjCPointerType = '^',
    NSObjCStringType = '*',
    NSObjCArrayType = '[',
    NSObjCUnionType = '(',
    NSObjCBitfield = 'b'
} API_DEPRECATED

测试运行结果

2018-01-08 18:10:29.520415+0800 testInvocation[97123:4268055] run:byCar-(null)
2018-01-08 18:10:29.520561+0800 testInvocation[97123:4268055] type = @
2018-01-08 18:10:29.520673+0800 testInvocation[97123:4268055] run:test1-test2



 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值