NSInvocation Notes
iOS 中一般用 performSelector
系列方法调用某个对象的方法消息,但是参数过多就不太方便,这时候就可以用 NSInvocation。一个简单的例子:
NSMethodSignature *sig = [self methodSignatureForSelector:@selector(addAlbum:atIndex:)];
NSInvocation *action = [NSInvocation invocationWithMethodSignature:sig];
[action setTarget:self]; //0
[action setSelector:@selector(addAlbum:atIndex:)]; //1
[action setArgument:&deletedAlbum atIndex:2]; //2
[action setArgument:¤tAlbumIndex atIndex:3]; //3
[action retainArguments];
[action invoke];
NSMethodSignature
直译就是方法签名,保存了方法的参数类型和返回值信息 (type information for the arguments and return value of a method)。 通过方法签名信息就可以完整构建一个 invocation,对各个参数进行赋值后激活执行,也就完成了对象方法调用。
再看 NSMethodSignature 一段文档:
Indices begin with 0. The hidden arguments self (of type id) and _cmd (of type SEL) are at indices 0 and 1; method-specific arguments begin at index 2.
NSInvocation 第一步设定 Target(0),第二步设定 Selector(1),然后从 index 2 开始依次对参数赋值,因为 0/1 已被 Target/Selector 占用。要注意赋值的时候传的都是 指针 ,如果赋值参数可能会被释放,要记得 retainArguments。如果需要 NSInvocation 执行后的返回值:
NSString *returnString = nil; //假定返回值类型为 NSString
[action getReturnValue:&returnString];
最后附上 Three20 里用 NSInvocation 实现多参数 performSelector:
https://github.com/facebook/three20/blob/1.0.12/src/Three20Core/Sources/NSObjectAdditions.m#L89
- (id)performSelector:(SEL)selector
withObject:(id)p1
withObject:(id)p2
withObject:(id)p3
withObject:(id)p4
withObject:(id)p5
{
NSMethodSignature *sig = [self methodSignatureForSelector:selector];
if (sig) {
NSInvocation* invo = [NSInvocation invocationWithMethodSignature:sig];
[invo setTarget:self];
[invo setSelector:selector];
[invo setArgument:&p1 atIndex:2];
[invo setArgument:&p2 atIndex:3];
[invo setArgument:&p3 atIndex:4];
[invo setArgument:&p4 atIndex:5];
[invo setArgument:&p5 atIndex:6];
[invo invoke];
if (sig.methodReturnLength) {
id anObject;
[invo getReturnValue:&anObject];
return anObject;
} else {
return nil;
}
} else {
return nil;
}
}
Was this page helpful?