美文网首页
NSInvacation调用某个对象的方法

NSInvacation调用某个对象的方法

作者: 枫叶1234 | 来源:发表于2018-05-03 15:19 被阅读6次

1、performSelector:withObject:
优点:调用简单。
缺点:仅支持单一返回值,单一参数。
example:

 [self performSelector:@selector() withObject:nil];

2、NSInvocation
优点:可以处理多个返回值,多个参数
缺点:调用复杂
example:

SEL testSelector = @selector(invokeMethod:);

NSMethodSignature *signature= [[Abc class] instanceMethodSignatureForSelector:testSelector];

NSInvocation *invocation=[NSInvocation invocationWithMethodSignature:signature];

[invocation setTarget:self];

//参数传入,atIndex的下标需从2开始,0为target,1为selector

NSInteger index = 10086;

[invocation setArgument:&index atIndex:2];

//消息调用

[invocation invoke];

 

//获得返回值类型

const char *returnType = signature.methodReturnType;

//声明返回值变量

id value;

//如果没有返回值,则returnValue = nil

if( !strcmp(returnType, @encode(void)) )

{

  value =  nil;

}

//如果返回值为对象

else if( !strcmp(returnType, @encode(id)) )

{

  [invocation getReturnValue:&value];

}

//如果返回值为普通类型NSInteger  BOOL

else

{

  //返回值长度

  NSUInteger length = [signature methodReturnLength];

  //根据长度申请内存

  void *buffer = (void *)malloc(length);

  //为变量赋值

  [invocation getReturnValue:buffer];

  if( !strcmp(returnType, @encode(BOOL)) )

  {

    value = [NSNumber numberWithBool:*((BOOL*)buffer)];

  }

  else if( !strcmp(returnType, @encode(NSInteger)) )

  {

    value = [NSNumber numberWithInteger:*((NSInteger*)buffer)];

  }

  value = [NSValue valueWithBytes:buffer objCType:returnType];

}

NSInvocation应用与理解

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

一、初始化与调用

在官方文档中有明确说明,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");
}

注意:签名函数的参数数量要和调用函数的一致。测试后发现,当签名函数参数数量大于被调函数时,也是没有问题的。
调用多参数的方法,我们可以这样写:

- (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];
    [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对象,是可以有返回值的,然而这个返回值,并不是其所调用函数的返回值,需要我们手动设置:

- (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对象,也是取地址。

三、关于内存

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

相关文章

  • NSInvacation调用某个对象的方法

    1、performSelector:withObject:优点:调用简单。缺点:仅支持单一返回值,单一参数。exa...

  • PowerMockito使用方法和避坑指南

    常用方法 模拟对象 PowerMockito.spy(T object)可用于mock某个对象,调用该对象某个方法...

  • 获取Class对象的3种方式

    1、调用某个对象的getClass()方法,以获取该类的Class对象 2、调用某个类的class属性,以获取该类...

  • runtime - 消息转发

    通过前边的学习我们知道,某个类或者对象调某个方法实际上就是给这个类/对象发送消息,如果我们某个对象要调用某个方法,...

  • JS中的this浅析

    1.this指代全局对象: 2.作为对象方法的调用: 函数还可以作为某个对象的方法调用,这时this就指这个上级对...

  • super关键字

    super的作用: 直接调用父类中的某个方法 super处在对象方法中,那么就会调用父类的对象方法,super处在...

  • oc 方法

    super 关键字: 1:可以直接调用父类的某个方法。 2:super 处在对象方法中,就会调用父类的对象方法。 ...

  • jQuery动画队列

    jQuery 动画队列 当在jQuery对象上调用动画方法时,如果对象正在执行某个动画效果,那么新调用的动画方法就...

  • js中的call方法的使用

    调用某个对象中的函数方法,在另一个对象上使用它

  • Java设计模式----代理模式

    核心作用: 通过代理,控制对对象的访问!可以详细控制访问某个(某类)对象的方法,在调用这个方法前做前置处理,调用这...

网友评论

      本文标题:NSInvacation调用某个对象的方法

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