不一样的方式实现performSelector接收多个参数

开发中偶尔有需求使用performSelector实现多个参数,
常规的方式是自定义一个performSelector方法并接收一个数组作为参数

- (id)performSelector:(SEL)selector withObjects:(NSArray *)objects;

在方法内部通过遍历数组,获取方法的参数,这确实是个好方法,
不过当我们需要给某个参数传递nil的时候,这个方法就不适用了,因为数组中不能存nil

下面尝试一种非常规的方法,请看~

/// 该方法接收一个方法的签名,和一个可变参数
- (id)performSelector:(SEL)aSelector withObjects:(id)object,... {
   
    // 方法签名(方法的描述)
    NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:aSelector];
    if (signature == nil) {
        NSAssert(false, @"牛逼的错误,找不到 %@ 方法",NSStringFromSelector(aSelector));
    }
    // 包装方法
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
    // 设置方法调用者
    invocation.target = self;
    // 设置需要调用的方法
    invocation.selector = aSelector;
    // 获取除去self、_cmd以外的参数个数
    NSInteger paramsCount = signature.numberOfArguments - 2;
    // 设置参数
    va_list params;
    va_start(params, object);
    int i = 0;
    // [GKEndMark end] 是自定义的结束符号,仅此而已,从而使的该方法可以接收nil做为参数
    for (id tmpObject = object; (id)tmpObject != [GKEndMark end]; tmpObject = va_arg(params, id)) {
        // 防止越界
        if (i >= paramsCount) break;
        // 去掉self,_cmd所以从2开始
        [invocation setArgument:&tmpObject atIndex:i + 2];
        i++;
    }
    va_end(params);
    // 调用方法
    [invocation invoke];
    // 获取返回值
    id returnValue = nil;
    if (signature.methodReturnType) {
        [invocation getReturnValue:&returnValue];
    }
    return returnValue;
}
​```
###下面是自定义的结束符号类的具体实现
```objc
#import "GKEndMark.h"
@implementation GKEndMark
+ (instancetype)end {
    static id instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[self class] new];
    });
    return instance;
}
@end

具体使用

- (void)viewDidLoad {
    [super viewDidLoad];
    // [GKEndMark end] 为自定义的结束符号,你也可以自己随便自定义一个~ 只是为了让参数可以传nil
    NSString * resultStr = [self performSelector:@selector(resultStringWithStr1:str2:str3:) withObjects:@"大神",nil,@"带我飞",@"飞飞飞",[GKEndMark end]];
    
    NSLog(@"输出结果 %@",resultStr);
}

- (NSString *)resultStringWithStr1:(NSString *)str1 str2:(NSString *)str2 str3:(NSString *)str3 {
   
    NSLog(@"各参数的值: str1 = %@ , str1 = %@, str1 = %@",str1, str2, str3);
    
    NSString * str = str1;
    if (str2) {
       str =  [str1 stringByAppendingString:str2];
    }
    
    if (str3) {
        return [str stringByAppendingString:str3];
    }
    return str;
}

控制台输出结果如下

Paste_Image.png

以上为方法的具体实现,已经做了详细的注释了,就不多做解释了,
不过该方法还有个局限性就是当调用的方法返回值不是对象类型时就会崩了
(不过系统的这类似的方法也没有返回基本数据类型的,不知道是不是我想太多了)
想了蛮久不知道该如何解决,如果你有好的解决方案,请联系我,谢谢~
需要用到数据库的请看:http://www.jianshu.com/p/0e598147debc

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 140,137评论 20 594
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 89,726评论 13 124
  • 第5章 引用类型(返回首页) 本章内容 使用对象 创建并操作数组 理解基本的JavaScript类型 使用基本类型...
    千机楼阅读 947评论 0 4
  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    萌萌的小伟哥阅读 703评论 0 9
  • 刚刚洗完澡敷了个面膜,想在心里默默地给自己加个油,从最初的跑步三四圈就累到不行的体力到现在跑五公里根本不喘...
    Fan小星阅读 45评论 0 0