如何更安全的使用Block
来源:互联网 发布:八陆融通网络贷款 编辑:程序博客网 时间:2024/05/16 04:41
http://www.starfelix.com/blog/2014/10/19/ru-he-geng-an-quan-de-shi-yong-block/
前段时间,在公司的项目中发现了内存泄露。查到最后发现是由于没有正确使用Block导致的内存引用循环。简单的解决方案就是补上关键字__weak
。那么问题来了,为何[UIView animateWithDuration:animations:completion:]或者GCD中可以不需要声明__weak呢?
如何选择回调方式
在讲这个问题之前,我们先看看Objcio上是怎么判断使用何种回调方式:
从这张图可以看到选择block的回掉方式的前提条件是sender能保证将callback被设为nil。定这个条件的目的是为了避免内存泄露。为何这样可以避免内存泄露呢?我们先看看通常我们是如何解决由使用block引入的内存引用循环问题。
引用循环
下面是一个内存引用循环的例子
这里可以看到,UsersViewController
持有一个block的强引用。如果一个不小心,我们会写出下面这样的代码:
self持有了对completion的强引用,而completion的代码块内引用了self会引起对self的强引用,这便是一个经典的引用循环的案例。
在MRC下,__block id x;
可以让block不强引用x。在ARC下,__block id x;
默认的行为会强引用x。为了在ARC下解决这个问题,你可以使用__unsafe_unretained __block id x;
。但是,这样做非常危险,因为当你的block里访问x时,x可能已经被释放了,变成野指针。你有两个更好的解决办法,一是换成使用__weak
,二是在block内设置__block
值为nil来打破引用循环。
如下:
1.使用__weak来表示对self的弱引用(代码里面不直接使用weakSelf的原因是为了在block里面保持对self的强引用,避免代码运行到一半self被释放)
2.使用__block关键字修饰self,然后在block里设置为nil
更友好的方式
这个时候我们的疑问来了,既然都可以解决内存循环引用的问题,为何还会有前面这个条件呢? 原因就是这种方式严重依赖调用者的使用方式,在日常使用中带来严重的代码质量隐患。而在苹果的sdk中几个使用block的方法中调用者都不需要特别的处理。 下面是一个测试代码:
上面代码的作用是进入一个controller后然后延时30s打印一个log,为了方便分析内存,我们使用的是mrc。使用Instructment分析内存如下:
从图片我们可以看到,temp是在30s后被释放。从Responsible Caller我们可以得出结论,block被持有,然后在30s触发执行后被释放。block中被capture的变量也被释放。如此也避免了内存问题。 把代码修改一下:
同样使用Instructment分析,结果等到NSLog代码执行的时候代码crash了,内存记录如下:
这说明,如果我们滥用__block,可能会出现在block运行的时候,访问对象已经被释放,造成访问野指针错误。 系统SDK向我们展示的是一种更友好使用block的方式,让调用者不需要担心内存引用循环也不会有访问野指针的风险。
结论
1.block的持有方式必须保证是copy,这样block中capture的对象才会被retain,保证block在执行的时候capture对象不会被提前释放。
2.为了避免引用循环,被copy的block必须保证在某个时刻被释放,以破坏引用循环。使得所有对象能被正常的释放。
- 如何更安全的使用Block
- 如何更安全的使用Block
- 如何更安全的使用Block
- 如何更安全的使用Block
- 如何更安全的使用Block
- 如何更安全的部署SSL证书
- Android中更安全的使用AsyncTask
- 如何让网站更安全
- 网站改版如何更安全
- 如何配置apache更安全
- 如何让你的Web服务器日志文件更安全?
- 如何让自己的Windows 7系统更安全
- MySQL 5.6 如何更安全的处理密码
- MySQL 5.6 如何更安全的处理密码
- 如何设置让我们的无线路由器更安全
- 如何设置 PHP.ini 让你的PHP更安全
- 如何让自己的服务器更安全些
- 如何让我们的OpenSSH更安全&攻防对抗
- 云计算技术的产生、概念、原理、应用和前景
- block使用小结、在arc中使用block、如何防止循环引用
- 笔记:Hadoop权威指南 第1章 初识Hadoop
- samba 下载问题 samba not found on UART的解决方法
- java回收机制
- 如何更安全的使用Block
- Unable to execute dex: Multiple dex files define 解决方法
- UVA - 10340 All in All
- Linux的chkconfig命令详解
- 一个标准的javaBean,试下微博显示
- 关于block坑爹的retain Cycle
- 数据结构模版----单链表SimpleLinkList[不带头结点&&伪OO](C语言实现)
- linux下编写汇编的Helloworld
- 分解质因数