iOS NSInvocation应用与理解

IOS中有一个类型是SEL,它的做用很类似与函数指针,经过performSelector:withObject:函数能够直接调用这个消息。可是perform相关的这些函数,有一个局限性,其参数数量不能超过2个,不然要作很麻烦的处理,与之相对,NSInvocation也是一种消息调用的方法,而且它的参数没有限制。这两种直接调用对象消息的方法,在IOS4.0以后,大多被block结构所取代,只有在很老的兼容性系统中才会使用,简单用法总结以下:函数

1、初始化与调用测试

在官方文档中有明确说明,NSInvocation对象只能使用其类方法来初始化,不可以使用alloc/init方法。它执行调用以前,须要设置两个方法:setSelector: 和setArgument:atIndex:指针

- (void)viewDidLoad {
    [super viewDidLoad];
    SEL myMethod = @selector(myLog);
    //建立一个函数签名,这个签名能够是任意的,但须要注意,签名函数的参数数量要和调用的一致。
    NSMethodSignature * sig  = [NSNumber instanceMethodSignatureForSelector:@selector(init)];
    //经过签名初始化
    NSInvocation * invocatin = [NSInvocation invocationWithMethodSignature:sig];
    //设置target
    [invocatin setTarget:self];
    //设置selecteor
    [invocatin setSelector:myMethod];
    //消息调用
    [invocatin invoke];
    
}
-(void)myLog{
    NSLog(@"MyLog");
}

注意:签名函数的参数数量要和调用函数的一致。测试后发现,当签名函数参数数量大于被调函数时,也是没有问题的。code

调用多参数的方法,咱们能够这样写:orm

- (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);
}

注意:一、这里设置参数的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];
    [invocatin setArgument:&myMethod2 atIndex:1];
    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);
}

二、这里的传参方式必须是传递参数地址。内存

2、NSInvocation的返回值文档

NSInvocation对象,是能够有返回值的,然而这个返回值,并非其所调用函数的返回值,须要咱们手动设置:get

- (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];
    ViewController * view = self; 
    int a=1;
    int b=2;
    int c=3;
    [invocatin setArgument:&view atIndex:0];
    [invocatin setArgument:&myMethod2 atIndex:1];
    [invocatin setArgument:&a atIndex:2];
    [invocatin setArgument:&b atIndex:3];
    [invocatin setArgument:&c atIndex:4];
    [invocatin retainArguments];
    //咱们将c的值设置为返回值
    [invocatin setReturnValue:&c];
    int d;
    //取这个返回值
    [invocatin getReturnValue:&d];
    NSLog(@"%d",d);
    
}
-(int)myLog:(int)a parm:(int)b parm:(int)c{
    NSLog(@"MyLog%d:%d:%d",a,b,c);
    return a+b+c;
}

注意:这里的操做传递的都是地址。若是是OC对象,也是取地址。it

3、关于内存

能够注意到- (void)retainArguments;这个方法,它会将传入的全部参数以及target都retain一遍。

专一技术,热爱生活,交流技术,也作朋友。

——珲少 QQ群:203317592

相关文章
相关标签/搜索