开发中偶尔有需求使用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
class
]
new
];
});
return
instance;
}
@end
具体使用请看下图
|
以上为方法的具体实现,已经做了详细的注释了,就不多做解释了,
不过该方法还有个局限性就是当调用的方法返回值不是对象类型时就会崩了(系统的这类似的方法也没有返回基本数据类型的,不知道是不是我想太多了,)