(1)用法
NSInvocation是调用函数的另一种方式,它将调用者,函数名,参数封装到一个对象,然后通过一个invoke函数来执行被调用的函数,其思想就是命令者模式,将请求封装成对象。
例如,有这样一个类:
@implementation CA
-(int)AddA:(int)a andB:(int)b
{
return a + b;
}
@end
一般调用函数的方式是:
CA *ca = [CA new];
int result = [ca AddA:2 andB:3];
或者用performSelector,但是后者只能有一个参数,所以对于有多个参数的情况,就可以用NSInvocation来调用。
示例代码:
CA *ca = [CA new];
NSMethodSignature *sig= [[CA class] instanceMethodSignatureForSelector:@selector(AddA:andB:)]; //根据selector得到一个签名对象
NSInvocation *invocation=[NSInvocation invocationWithMethodSignature:sig];//根据该签名对象创建一个NSInvocation对象
invocation.target = ca;//指定调用函数的对象
invocation.selector = @selector(AddA:andB:);//指定要调用的函数名
int a = 20;
int b = 30;
[invocation setArgument:&a atIndex:2];//指定参数,以指针方式,并且第一个参数的起始index是2,因为index为1,2的分别是self和selector
[invocation setArgument:&b atIndex:3];
[invocation retainArguments];//因为NSInvocation不会自己去retain参数,因此需要用户去retain,当然本例中其实没必要
[invocation invoke];
//获取返回值的过程略有点复杂,需要根据起类型长度分配空间,然后转为对象
//如果是int,BOOL等简单类型,返回的对象是NSNumber
//如果是其他类型的对象,返回的对象是NSValue
//判断返回值类型,用strcmp(returnType, @encode(NSInteger))
const char *returnType = sig.methodReturnType;
id returnValue;
NSUInteger length = [sig methodReturnLength];
void *buffer = (void *)malloc(length);
[invocation getReturnValue:buffer];
returnValue = [NSNumber numberWithInteger:*((NSInteger*)buffer)];//int的情况
//returnValue = [NSNumber numberWithBool:*((BOOL*)buffer)]; //bool 的情况
//returnValue = [NSValue valueWithBytes:buffer objCType:returnType];// 其他类型的情况
int result = [returnValue intValue];
NSLog(@"result=%d",result);
(2) 用到NSInvocation的一些场合
[NSTimer scheduledTimerWithTimeInterval:0.1 invocation:invocation repeats:YES]
NSInvocationOperation //它是NSOperation的派生类,用NSInvoation来初始化
(void)forwardInvocation:(NSInvocation *)anInvocation
这个函数与forwardTargetWithSelector类似,当某个对象收到一个selector消息,但该对象没有实现该selector,且实现forwardInvocation,那么系统会构造一个NSInvocation对象,并调用forwardInvocation,这样在函数里面,用户就可以用[invocation invokeWithTarget:friend];来让另一个对象来执行这个selector.
要实现这个函数,还必须实现methodSignatureForSelector,因为这个anInvocation是系统构造的,构造这个对象需要有签名对象,这个对象必须由用户提供。所以这个函数用起来比forwardingTargetForSelector麻烦
另外,由于使用forwardInvocation可以使得一个对象将它没有实现的方法转发给其他对象,因此可以变相的实现多继承。
参考链接:http://www.cnblogs.com/pengyingh/articles/2359199.html