iOS performSelector传递两个以上参数

如题如何使用performSelector传递两个以上参数以及如何传递结构体
分两个问题:
1.如何传递两个以上参数
2.如何传递结构体

1 如何传递两个以上参数

有四种方式可以实现
1.将所有参数放入一个字典/数组传过去
2.使用objc_msgSend()传递
3.用NSInvocation传递
4.利用runtime特性传递

a 将所有参数放入一个字典/数组传过去

思路:这种方式就是将所有参数都放到一个字典/数组中,然后将数组/字典当作一个参数传给要调用的方法。

注意点:这种方式需要改动要调用的方法的取参数的方式,比如使用字典传递,双方约定每一个参数放入字典对应的key是什么,在方法哪部才能从对应的key中取出参数值。

具体代码如下:

//封装参数
    NSDictionary *dic = @{@"param1":@"this is a string",@"param2":@[@2,@3,@3],@"param3":@123};
//调用方法
    [self performSelector:@selector(testFunctionWithParams:) withObject:dic];

- (void)testFunctionWithParams:(NSDictionary *)paramDic {
    NSLog(@"%s dic:%@",__FUNCTION__, paramDic);
}

b 使用objc_msgSend()传递

思路:利用objc_msgSend() 方法可以传递多个参数的特性调用方法执行

具体代码如下:

((void (*)(id,SEL,NSString *, NSArray *, NSInteger))objc_msgSend)(self, @selector(textFunctionWithParam:param2:param3:),@"111",@[@2,@3],123);

//有三个参数的方法
-(void)textFunctionWithParam:(NSString *)param1 param2:(NSArray *)param2 param3:(NSInteger)param3 {
    NSLog(@"param1:%@, param2:%@, param3:%ld",param1, param2, param3);
}

c 用NSInvocation传递

思路:将方法调用采用NSInvocation调用,NSInvocation 不限制参数数量

这里可以了解一下NSInvocation的用法https://www.jianshu.com/p/e24b3420f1b4

具体代码如下:

//可以传多个参数的方法
- (id)performSelector:(SEL)selector withObjects:(NSArray *)objects
{
    // 方法签名(方法的描述)
    NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:selector];
    if (signature == nil) {
        
        //可以抛出异常也可以不操作。
    }
    
    // NSInvocation : 利用一个NSInvocation对象包装一次方法调用(方法调用者、方法名、方法参数、方法返回值)
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
    invocation.target = self;
    invocation.selector = selector;
    
    // 设置参数
    NSInteger paramsCount = signature.numberOfArguments - 2; // 除self、_cmd以外的参数个数
    paramsCount = MIN(paramsCount, objects.count);
    for (NSInteger i = 0; i < paramsCount; i++) {
        id object = objects[i];
        if ([object isKindOfClass:[NSNull class]]) continue;
        [invocation setArgument:&object atIndex:i + 2];
    }
    
    // 调用方法
    [invocation invoke];
    
    // 获取返回值
    id returnValue = nil;
    if (signature.methodReturnLength) { // 有返回值类型,才去获得返回值
        [invocation getReturnValue:&returnValue];
    }
    
    return returnValue;
}

//调用方法
NSArray *paramArray = @[@"112",@[@2,@13],@12];
    [self performSelector:@selector(textFunctionWithParam:param2:param3:) withObjects:paramArray];


//要调用的方法
-(void)textFunctionWithParam:(NSString *)param1 param2:(NSArray *)param2 param3:(NSInteger)param3 {
    NSLog(@"param1:%@, param2:%@, param3:%ld",param1, param2, param3);
}


2 如何传递结构体

思路:将结构体封装成NSValue对象

关于NSValue的更多内容请参照:http://nshipster.cn/nsvalue/

typedef struct TTTestStrout{
   int aaa;
   int bbb;
} testStrout;

   //传结构体
   testStrout testS = {10000, 1234};
   NSValue *value = [NSValue valueWithBytes:&testS objCType:@encode(testStrout)];
   //dic
   NSDictionary *dataDic = @{@"param1":@"ssfs",@"param2":@[@333,@32343],@"param3":value};

   [self performSelector:@selector(testFunctionWithParams:) withObject:dataDic];


- (void)testFunctionWithParams:(NSDictionary *)paramDic {
   NSLog(@"%s dic:%@",__FUNCTION__, paramDic);
   NSValue *paramValue = paramDic[@"param3"];
   testStrout paramStrout;
   [paramValue getValue:¶mStrout];
   NSLog(@"%d",paramStrout.aaa);
   
}

你可能感兴趣的:(iOS performSelector传递两个以上参数)