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

本文介绍了一种在Objective-C中使用 performSelector 实现多参数传递的方法,解决了数组不能存储 nil 的问题,并通过自定义结束标记允许 nil 参数的传递。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

开发中偶尔有需求使用performSelector实现多个参数,

常规的方式是自定义一个performSelector方法并接收一个数组作为参数

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

在方法内部通过遍历数组,获取方法的参数,这确实是个好方法,

不过当我们需要给某个参数传递nil的时候,这个方法就不适用了,因为数组中不能存nil


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

1
2
/// 该方法接收一个方法的签名,和可变参数
- (id)performSelector:(SEL)aSelector withObjects:(id)object,...;

下面看看具体实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
- (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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 该类仅仅用于自定义的结束符号
#import "GKEndMark.h"
 
@implementation GKEndMark
 
+ (instancetype)end {
    static id instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[self classnew];
    });
     
    return instance;
}
 
@end
 
具体使用请看下图

1.png

以上为方法的具体实现,已经做了详细的注释了,就不多做解释了,

不过该方法还有个局限性就是当调用的方法返回值不是对象类型时就会崩了(系统的这类似的方法也没有返回基本数据类型的,不知道是不是我想太多了,)


评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值