源文在此
IOS中有一个类型是SEL,它的作用很相似与函数指针,通过performSelector:withObject:函数可以直接调用这个消息。但是perform相关的这些函数,有一个局限性,其参数数量不能超过2个,否则要做很麻烦的处理,与之相对,NSInvocation也是一种消息调用的方法,并且它的参数没有限制。这两种直接调用对象消息的方法,在IOS4.0之后,大多被block结构所取代,只有在很老的兼容性系统中才会使用,简单用法总结如下
- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
一、初始化与调用
在官方文档中有明确说明,NSInvocation对象只能使用其类方法来初始化,不可使用alloc/init方法。它执行调用之前,需要走四步”
- 1、获取target的SEL方法签名
- 2、设置执行目标target
- 3、设置执行方法SEL
- 4、执行
NSInvocation 对象封装运行时库以向接收器转发执行消息所需的必要信息,
由于NSInvocation 是调用的一个通用的通用层面的抽象,苹果公司的框架设计师在设计NSInvocation 类的基础设施时,当然对我们的实际接收器、调用器、选择器等一无所知。因此在创建NSInvocation 对象时,需要1️以NSMethodSignature的形式,提供必要的信息。NSMethodSignature对象包含了方法调用的所有参数和返回值类型。
NSMethodSignature* methodSig = [target methodSignatureForSelector:action];
if(methodSig == nil) {
return nil;
}
const char* retType = [methodSig methodReturnType];
if (strcmp(retType, @encode(void)) == 0) {
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
[invocation setArgument:¶ms atIndex:2];
[invocation setSelector:action];
[invocation setTarget:target];
[invocation invoke];
return nil;
}
传参
注意:签名函数的参数数量要和调用函数的一致。测试后发现,当签名函数参数数量大于被调函数时,也是没有问题的。
调用多参数的方法,我们可以这样写:
- (void)viewDidLoad {
[super viewDidLoad];
SEL myMethod = @selector(myLog:parm:parm:);
NSMethodSignature * sig = [[self class] instanceMethodSignatureForSelector:myMethod];
NSInvocation * invocatin = [NSInvocation invocationWithMethodSignature:sig];
[invocatin setTarget:self];
[invocatin setSelector:myMethod2];
int a=1;
int b=2;
int c=3;
[invocatin setArgument:&a atIndex:2];
[invocatin setArgument:&b atIndex:3];
[invocatin setArgument:&c atIndex:4];
[invocatin invoke];
}
-(void)myLog:(int)a parm:(int)b parm:(int)c{
NSLog(@"MyLog%d:%d:%d",a,b,c);
}
注意:1、这里设置参数的Index 需要从2开始,因为前两个被selector和target占用。下面这样写也没有任何问题:
- (void)viewDidLoad {
[super viewDidLoad];
SEL myMethod = @selector(myLog:parm:parm:);
SEL myMethod2 = @selector(myLog);
NSMethodSignature * sig = [[self class] instanceMethodSignatureForSelector:myMethod];
NSInvocation * invocatin = [NSInvocation invocationWithMethodSignature:sig];
ViewController * view = self;
[invocatin setArgument:&view atIndex:0];//target 作为参数传递
[invocatin setArgument:&myMethod2 atIndex:1];//selector 作为参数传递
int a=1;
int b=2;
int c=3;
[invocatin setArgument:&a atIndex:2];
[invocatin setArgument:&b atIndex:3];
[invocatin setArgument:&c atIndex:4];
[invocatin retainArguments];
[invocatin invoke];
}
-(void)myLog:(int)a parm:(int)b parm:(int)c{
NSLog(@"MyLog%d:%d:%d",a,b,c);
}






网友评论