NSMethodSignature、NSInvocation进行消息转发

方法的一般调用方式:

1、performSelector:withObject;

2、NSInvocation

什么时候使用NSInvocation:

performSelector:withObject能完成简单的调用。但是对于>2个的参数或者有返回值的处理,那performSelector:withObject就显得费力了,这种情况下,我使用NSInvocation就显得相对简单些。

NSMethodSignature和NSInvocation的概述:

使用NSMethodSignature 和 NSInvocation 不仅可以完成对method的调用,也可以完成block的调用

NSMethodSignature:NSMethodSignature用于描述method的类型信息:返回值类型,及每个参数的类型

提供几个例子供参考:

- (id)performSelector:(SEL)aSelector withTheObjects:(NSArray*)objects{
    //1、创建签名对象
    //  NSMethodSignature*signature = [self methodSignatureForSelector:aSelector];
    NSMethodSignature*signature = [[self class] instanceMethodSignatureForSelector:aSelector];
    //2、判断传入的方法是否存在
    if (!signature) {
        //传入的方法不存在 就抛异常
        NSString*info = [NSString stringWithFormat:@"-[%@ %@]:unrecognized selector sent to instance",[self class],NSStringFromSelector(aSelector)];
        @throw [[NSException alloc] initWithName:@"方法没有" reason:info userInfo:nil];
        return nil;
    }
    //3、创建NSInvocation对象
    NSInvocation*invocation = [NSInvocation invocationWithMethodSignature:signature];
    //4、保存方法所属的对象
    invocation.target = self;           // index 0
    invocation.selector = aSelector;    // index 1

    //5、设置参数
    NSInteger arguments = signature.numberOfArguments -2;
    NSUInteger objectsCount = objects.count;
    NSInteger count = MIN(arguments, objectsCount);
    [self setInv:invocation andArgs:objects argsCount:count];

    //6、调用NSinvocation对象
    [invocation invoke];

    //7、获取返回值
    id res = nil;
    if (signature.methodReturnLength ==0) return nil;
    //getReturnValue获取返回值
    [invocation getReturnValue:&res];
    return res;
}
- (nullable id)performSelectorWithTheArgs:(SEL)sel, ...{
    NSMethodSignature * sig = [self methodSignatureForSelector:sel];
    if (!sig) { [self doesNotRecognizeSelector:sel]; return nil; }
    NSInvocation *inv = [NSInvocation invocationWithMethodSignature:sig];
    if (!inv) { [self doesNotRecognizeSelector:sel]; return nil; }
    // 设置消息接收者
    [inv setTarget:self];   // index = 0
    // 设置调用的方法
    [inv setSelector:sel];  // index = 1
    // 获取参数
    va_list args;
    va_start(args, sel);
    [self setInv:inv sigT:sig andArgs:args];
    va_end(args);
    [inv invoke];
    // 获取返回值
    id res = nil;
    if (sig.methodReturnLength ==0) return nil;
    //getReturnValue获取返回值
    [inv getReturnValue:&res];
    return res;
}
#pragma mark - 传递一个值的block
- (void)performSelectorWithTheBlock:(void(^)(int value))block {
    // 获取block
    NSMethodSignature *signature = aspect_blockMethodSignature(block,NULL);
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
    [invocation setTarget:block];
    // 此处待考虑
    int a=2;
    [invocation setArgument:&a atIndex:1];
    [invocation invoke];
}

调用方式:

UIView *view = [[UIView alloc]initWithFrame:CGRectMake(100, 100, 30, 30)];
view.backgroundColor = [UIColor redColor];
[self.view addSubview:view];
//[view performSelector:@selector(setBackgroundColor:) withTheObjects:@[[UIColor greenColor]]];
[view performSelectorWithTheArgs:@selector(setBackgroundColor:), [UIColor greenColor], [UIColor yellowColor]];

资源代码: https://github.com/MisterZhouZhou/iOSToolsDemo/blob/master/OCToolsDemo/OCToolsDemo/OCTools/Category/NSObject%2BperformSelector.m

参考资源:

  1. http://www.jianshu.com/p/da96980648b6
  2. https://github.com/ibireme/YYKit/blob/master/YYKit/Base/Foundation/NSObject%2BYYAdd.m
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值