iOS中performSelector实现多参数传递
关于performSelector实现多个参数传递,其实有2种方案,第一种是使用 NSInvocation,第二种是封装参数。按照参数传递的原则,例如c++中的线程,我们只能传递一个参数,但我们可以将参数封装进结构体或者class也是一种优秀的方案。
两种方法的比较,第一种使用了Runtime反射机制,效率又说折扣,可读性也不好好,第二种方法,效率较高,可读性也比较好。所以对比而言,推荐第二种将参数封装进结构体或者对象,作为DTO的作用。
第一种方法NSInvocation:
- (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;
}
当然,为了保证线程意义,我们可以如下
- (void) performSelectorOnMainThread:(SEL)selector withObject:(id)arg1 withObject:(id)arg2 waitUntilDone:(BOOL)wait{
NSMethodSignature *sig = [self methodSignatureForSelector:selector];
if (!sig)
return;
NSInvocation* invo = [NSInvocation invocationWithMethodSignature:sig];
[invo setTarget:self];
[invo setSelector:selector];
[invo setArgument:&arg1 atIndex:2];
[invo setArgument:&arg2 atIndex:3];
[invo retainArguments];
[invo performSelectorOnMainThread:@selector(invoke) withObject:nil waitUntilDone:wait];
}
第二种方法[参数封装](推荐)
我们还可以将参数进行封装成一个结构体,Class,或者是字典和其他集合,然后定义一个单参数的方法也是可取的,这里就不给出例子了
-(void)askWorker:(NSString *) name withID:(NSInteger) money AtDate:(NSDate *)date
{
NSLog(@"%@---@ld---%@",name,(long)money,date);
}
-(void) askWorker:(NSObject *)args
{
if([args isKindOfClass:[NSDictonary class]]
{
NSDictionary * dict = (NSDictionary *)args;
[self askWorker:dict[@"name"] withID:(NSInteger)dict[@"ID"] AtDate:dict[@"date"]];
}else if([args isKindOfClass:[UserProfile class]]){
UserProfile * profile = (UserProfile *)args;
[self askWorker:profile.name withID:profile.ID AtDate:profile.date];
}
}
调用如下
NSDictionary * dict = @{@"name":@"zhangsan",@"ID":@20102847,@"date":[NSDate dateWithTimeIntervalSince1970:0]};
[[TestDict share] performSelector:@selector(askWorker:) withObject:dict];
来源:oschina
链接:https://my.oschina.net/u/2256215/blog/644117