美文网首页iOS在路上iOS开发iOS开发
iOS performSelector传递两个以上参数

iOS performSelector传递两个以上参数

作者: 7分醉 | 来源:发表于2018-05-27 14:04 被阅读363次

    如题如何使用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:&paramStrout];
       NSLog(@"%d",paramStrout.aaa);
       
    }
    

    相关文章

      网友评论

        本文标题:iOS performSelector传递两个以上参数

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