在ios直接调用某个对象的消息是方法有两种:
一:performselector:withObject:
二:invocation
第一种方式比较简单,能完成简单的调用。但是对于>2个的参数或者有返回值的处理,那就需要做些额外工作才能搞定。那么在这种情况下,我们就可以使用NSInvocation来进行这些相对复杂的操作
NSInvocation可以处理参数、返回值。会java的人都知道凡是操作,其实NSInvocation就相当于反射操作。
//方法签名类,需要被调用消息所属的类AsynInvoke ,被调用的消息invokeMethod: NSMethodSignature *sig= [[AsynInvoke class] instanceMethodSignatureForSelector:@selector(invokeMethod:)]; //根据方法签名创建一个NSInvocation NSInvocation *invocation=[NSInvocation invocationWithMethodSignature:sig]; //设置调用者也就是AsynInvoked的实例对象,在这里我用self替代 [invocation setTarget:self]; //设置被调用的消息 [invocation setSelector:@selector(invokeMethod:)]; //如果此消息有参数需要传入,那么就需要按照如下方法进行参数设置,需要注意的是,atIndex的下标必须从2开始。原因为:0 1 两个参数已经被target 和selector占用 NSInteger num=10; [invocation setArgument:&num atIndex:2]; //retain 所有参数,防止参数被释放dealloc [invocation retainArguments]; //消息调用 [invocation invoke]; //如果调用的消息有返回值,那么可进行以下处理 //获得返回值类型 const char *returnType = sig.methodReturnType; //声明返回值变量 id returnValue; //如果没有返回值,也就是消息声明为void,那么returnValue=nil if( !strcmp(returnType, @encode(void)) ){ returnValue = nil; } //如果返回值为对象,那么为变量赋值 else if( !strcmp(returnType, @encode(id)) ){ [invocation getReturnValue:&returnValue]; } else{ //如果返回值为普通类型NSInteger BOOL //返回值长度 NSUInteger length = [sig methodReturnLength]; //根据长度申请内存 void *buffer = (void *)malloc(length); //为变量赋值 [invocation getReturnValue:buffer]; //以下代码为参考:具体地址我忘记了,等我找到后补上,(很对不起原作者) if( !strcmp(returnType, @encode(BOOL)) ) { returnValue = [NSNumber numberWithBool:*((BOOL*)buffer)]; } else if( !strcmp(returnType, @encode(NSInteger)) ){ returnValue = [NSNumber numberWithInteger:*((NSInteger*)buffer)]; } returnValue = [NSValue valueWithBytes:buffer objCType:returnType]; }
调用步骤:
- (NSString *) myMethod:(NSString *)param1 withParam2:(NSNumber *)param2{ NSString *result = @"Objective-C"; NSLog(@"Param 1 = %@", param1); NSLog(@"Param 2 = %@", param2); return(result); } - (void) invokeMyMethodDynamically { SEL selector = @selector(myMethod:withParam2:); NSMethodSignature *methodSignature = [[self class] instanceMethodSignatureForSelector:selector]; NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature]; [invocation setTarget:self]; [invocation setSelector:selector]; NSString *returnValue = nil; NSString *argument1 = @"First Parameter"; NSNumber *argument2 = [NSNumber numberWithInt:102]; [invocation setArgument:&argument1 atIndex:2]; [invocation setArgument:&argument2 atIndex:3]; [invocation retainArguments]; [invocation invoke]; [invocation getReturnValue:&returnValue]; NSLog(@"Return Value = %@", returnValue); }
To do this, you need to follow these steps:
1. Form a SEL value using the name of the method and its parameter names (as
explained in Recipe 1.7).
2. Form a method signature of type NSMethodSignature out of your SEL value.
3. Form an invocation of type NSInvocation out of your method signature.
4. Tell the invocation what object you are targeting.
5. Tell the invocation what selector in that object you want to invoke.
6. Assign any arguments, one by one, to the invocation.
7. Invoke the method using the invocation object and demand a return value (if any).