美文网首页
NSInvocation应用与理解

NSInvocation应用与理解

作者: lltree | 来源:发表于2018-06-08 15:30 被阅读18次

源文在此
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:&params 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);
}

相关文章

网友评论

      本文标题:NSInvocation应用与理解

      本文链接:https://www.haomeiwen.com/subject/berasftx.html