【OC梳理】循环引用及解决
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了【OC梳理】循环引用及解决相关的知识,希望对你有一定的参考价值。
参考技术A 循环引用是ios开发中经常遇到的问题,它指的是两个或多个对象通过相互之间的强引用,形成了一个保留环,即使已经没有外部对象持有,也无法对其进行释放操作,也无法释放其占用的内存空间(引用计数器始终大于0)。举个简单的例子:
对象A持有对象B,对象B持有对象C,对象C持有对象A,这时候它们之间就形成了一个引用环:
这时候如果有一个对象D,引用了对象A,那么由于ABC之间的循环引用,它们的引用计数器如下:
那么即使D释放了对象A,A、B、C的引用计数器仍然都是1,它们都不会被释放回收。
由于循环引用的存在,使得产生循环引用的对象始终占有内存空间,过多的循环引用会导致程序的内存占用不断升高,最终导致程序Creach。
用weak而不是strong就能解决这个问题了:
Block的循环引用,主要是发生在ViewController中持有了block,比如:
同时在对callbackBlock进行赋值的时候又调用了ViewController的方法,比如:
就会发生循环引用,因为:ViewController->强引用了callback->强引用了ViewController,解决方法也很简单:
那是不是所有的block都会发生循环引用呢?其实不然,比如UIView的类方法Block动画,NSArray等的 类的遍历方法,都不会发生循环引用,因为当前控制器一般不会强引用一个类。
NSTimer是一种很容易忽略的循环引用的情况。
因为timer会强引用self,而self又持有了timer,这就造成了循环引用。
那么能不能像Block那样用一个weak指针解决呢?比如
但是其实并没有用,因为不管是weakSelf还是strongSelf,最终在NSTimer内部都会重新生成一个新的指针指向self,这是一个强引用的指针,结果就会导致循环引用。
如何解决呢?用NSProxy就是一个狠简便的方法
NSProxy本身是一个抽象类,它遵循NSObject协议,提供了消息转发的通用接口。NSProxy通常用来实现消息转发机制和惰性初始化资源。
使用NSProxy,你需要写一个子类继承它,然后需要实现init以及消息转发的相关方法:
创建NSTimer时,使用如下方法:
原理如下:
把虚线处变成了弱引用。于是,Controller就可以被释放掉,我们在Controller的dealloc中调用invalidate,就断掉了Runloop对Timer的引用,于是整个三个淡蓝色的就都被释放掉了。
参考文章: NSProxy与消息转发机制
Swift-闭包使用及解决循环引用问题
Swift中闭包使用参考OC中block使用,基本一致
// 闭包类型 首先写(参数列表)->(返回值类型) func loadData(callBack : (jsonData:String)->()){ dispatch_async(dispatch_get_global_queue(0, 0)) { print("网络请求\\(NSThread.currentThread())") dispatch_sync(dispatch_get_main_queue(), { print("获取到数据\\(NSThread.currentThread())") callBack(jsonData: "数据") }) } }
解决Swift中闭包循环引用有三种方法:
1.跟oc一样,使用weak(oc是__weakSelf)
2.简化第一种方法tools?.loadData({[weak self] (jsonData) in}) 这里self需要解包(推荐使用)
3.简化第一种方法tools?.loadData({[unowned self] (jsonData) in})这种方法当self为空就会崩溃
以上是关于【OC梳理】循环引用及解决的主要内容,如果未能解决你的问题,请参考以下文章