iOS NSInvocation的使用

参考:http://blog.csdn.net/zengconggen/article/details/38024625

在使用NStimer时需要在响应方法中传入多个参数,但是使用performSelector却只能传入两个参数,后来就看到方法中有一个是使用NSInvocation的,对这个类分析了解后发现正可满足要求。本篇文档可能有点浅显,基本的使用方式表述了出来,深层次的问题并未分析到,仅适合想初始了解其使用方式之友,后续如有深层次理解再来完善!

作用:NSInvocation的作用和performSelector:withObject:的作用是一样的:
—— 用于iOS 编程中调用某个对象的消息。
performSelector:withObject:调用一些参数较少的消息是比较方便的,但是对于参数个数大于2的消息,使用NSInvocation还是比较方便的。

因为NSInvocation是静态的呈现Objective-C的消息,也就是说,它把一个行动变成了一个对象。NSInvocation对象用于对象之间和应用程序之间存储和转发消息,主要通过NSTimer对象和分布式对象系统来完成。

performSelector与直接 调用和与NSInvocation的区别

1 . 与直接调用的区别:
performSelector是运行时系统负责去找方法的,在编译时不去做任何校验;如果直接调用编译器会自动检验。如果所用的那个方法不存在,那么直接调用在编译时就会发现(借助Xcode可以写完就发现),但如果使用performSelector一定是在运行时才能发现(不过此时系统已经崩溃); Cocoa支持在运行时向某个类添加方法,即方法编译时不存在,但是运行时存在,这时候必然需要使用performSelector去调用。所以为了程序的健壮性,会使用 respondsToSelector:(SEL)aSelector; 来检测。

直接调用方法时,一定要在头文件中声明该方法的使用,也要将头文件import进来。而使用performSelector时候,可以不用import头文件包含方法的对象,直接用performSelector调用即可。

优点:运行时进行直接调用 ,不需要import头文件

2 . performSelectorNSInvocation的区别
performSelector最多只能传入两个参数,如果使用NSInvocation可以传入许多参数。
使用例子:

SEL method = @selector(fireTimer:andDate:);
NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:method];

NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setTarget:self];
[invocation setSelector:method];
[invocation setArgument:&user atIndex:2];
[invocation setArgument:&date atIndex:3];  // 这里的两个参数就是对应着方法中的两个值来说的。

[invocation invoke];

如果使用了[NSTimer timerWithTimeInterval:2.0 invocation:invocation repeats:YES]; 这样就相当于调用了invoke

还存在一个问题,如果这个方法有返回值,你要怎样处理

  SEL selector = @selector(doSomeThingWithStr:andStr2:);
    NSMethodSignature *sig = [[self class] instanceMethodSignatureForSelector:selector];
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig];
    [invocation setTarget:self]; // 第0个参数
    [invocation setSelector:selector]; // 第1个参数

    NSString *arg1 = @"testdemo";
    NSString *arg2 = @"let's go";

    [invocation setArgument:&arg1 atIndex:2]; 
    [invocation setArgument:&arg2 atIndex:3];

    [invocation invoke];


    NSString *result;
    [invocation getReturnValue:&result];
    NSLog(@"result is %@",result);

在设置Enable Zombies后发现,是由于系统多次释放NSArray * resultSet造成的非法内存访问。
原因是在arc模式下,getReturnValue:仅仅是从invocation的返回值拷贝到指定的内存地址,如果返回值是一个NSObject对象的话,是没有处理起内存管理的。而我们在定义resultSet时使用的是__strong类型的指针对象,arc就会假设该内存块已被retain(实际没有),当resultSet出了定义域释放时,导致该crash。假如在定义之前有赋值的话,还会造成内存泄露的问题。
解决办法:
使用一个unretain的对象来获取返回值,或者 用void *指针来保存返回值,然后用__bridge来转化为OC对象。

// 方式一:

  __unsafe_unretained NSString *result;

    [invocation getReturnValue:&result];
    NSLog(@"result is %@",result);

//方式二:

//    void *result;
//    [invocation getReturnValue:&result];
//    NSLog(@"result is %@",(__bridge NSString *)result);
-(NSString *)doSomeThingWithStr:(NSString *)str1 andStr2:(NSString *)str2
{
    NSLog(@"str1 is %@, str2 is %@", str1, str2);
    return [str1 stringByAppendingString:str2];
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值