前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >NSInvocation与ARC的恩怨

NSInvocation与ARC的恩怨

原创
作者头像
forrestlin
发布2020-11-22 23:17:47
1.4K0
发布2020-11-22 23:17:47
举报
文章被收录于专栏:蜉蝣禅修之道蜉蝣禅修之道

背景

NSInvocation是iOS开发中常见的用来实现反射的方法,即通过传入方法名和参数等格式化的字符串后,即可调用指定的方法,虽然牺牲了运行性能,但是对于模块解耦确实是个杀手锏,而NSInvocation充分体现了OC通过消息传递来调用方法的特性,是iOS开发中解耦的利器。

问题

当我们需要获取NSInvocation调用方法的返回值时,会使用系统提供的- (void)getReturnValue:(id *retValue);方法,调用的代码大概如下面所示:

代码语言:txt
复制
NSMethodSignature *methodSignature = [AClass instanceMethodSignatureForSelector:NSSelectorFromString(action)];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];

[invocation setTarget:aInstance];
[invocation setSelector:NSSelectorFromString(action)];
NSObject *param1 = [[NSObject alloc] init];
[invocation setArgument:&param1 atIndex:2];

id resultValue;
[invocation invoke];
[invocation getReturnValue:&resultValue];
return resultValue;

假如上述代码不幸在ARC模式下运行,那么恭喜你获得crash一枚,而且堆栈栈顶多半是objc_retainobjc_release等,有经验的你肯定知道这意味着我们内存管理出问题了,大概率出现了野指针。这时机智的你肯定会拿出Zombie Object工具,这工具确实很有用,很快我们就可以定位出过度释放是发生在action方法调用过程中,经过一轮查证,问题最有可能就是出现在NSInvocation调用过程中了,那么是参数还是返回值过度释放呢?

假如是参数,那么我们通过retainArguments方法就理应解决了,可惜仍然发生了crash,情况并没有变化,因此crash真凶应该就锁定在action方法调用后的返回值了。经过参考苹果文档发现,getReturnValue过程中,只是将原本的返回值按字节拷贝到参数所指的地址,因此这时并没有进行retain操作,更加不会有objc_autoreleaseReturnValueobjc_retainAutoreleasedReturnValue这些编译器优化,因此这时我们假如将上述代码转成汇编,就会发现ARC帮我们在整个方法最后添加了release方法,以为returnValue默认是__strong修饰的,所以过度释放就发生在此处。

解决方法

经过一轮辗转查证,我们找到crash的罪魁祸首,那我们该怎么避免呢?

既然ARC帮我们多加了一次不必要的release,那么有没有办法让ARC不加release呢,有的,那就是给resultValue显示指定__unsafe_unretained修饰符,这个一直被我们认定为没用,不安全的修饰符,现在可以派上用场了,使用它,ARC自然就不会帮我们添加release,可是这样返回值在整个方法结束后就会被释放回收,所以,我们还需要再用一个__strong修饰的变量持有住该返回值,具体代码如下:

代码语言:txt
复制
id __unsafe_unretained tmpValue;
[invocation invoke];
[invocation getReturnValue:&tmpValue];
id resultValue = tmpValue;
return resultValue;

总结

内存问题以难以定位著称,我们需要多利用instrument中的工具辅助,一步步排除干扰,提高我们的效率。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • 问题
  • 解决方法
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档