循环引用
循环引用不做过多的解释,两个对象互相持有对方,谁都无法先被释放掉。循环引用经常是由于使用block而引起的,解决这种循环引用的方案主要是weakSelf
与strongSelf
。那具体为什么这两个Self
可以解决循环引用呢?在这里用简单解释下。
block强引用self
首先看一下什么情况下block
会强引用self
。我们知道block
在内存中有三种存放区域:
- 全局区:声明为全局变量的
block
。 - 栈区: 方法中声明的block,未被拷贝的。
- 堆区: 经过
copy
操作的block
,会被复制到堆区。
在block
被copy
到堆区的过程中,会对block
内部直接或者间接(引用self
的实例变量)引用的self
做retain
操作。如果恰巧这个block
是被self
持有的,这种情况下则发生了循环引用。
weakSelf
为了避免循环引用的产生,可以通过__weak
关键字,创建一个变量weakSelf
,引用但不持有self
,在self
被释放的时候这个变量自动变为nil
。简单来说就是这个变量不会导致self
的引用计数+1,但是可以通过这个变量访问self
。这样在block
中使用weakSelf
的时候,只是会引用weakSelf
这个变量,就不会产生循环引用问题了。
strongSelf
利用weakSelf
其实已经解决了循环引用的问题,但是在block中使用weakSelf
时会有问题:weakSelf
不一定什么时候会变为nil。因为block没有强引用self
,所以self
可能在block执行过程中被释放,此时weakSelf
也会变为nil,这样很可能出现问题。
所以理想的情况是block在开始执行时,要么self
已经是释放了,要么self
一直存在,直到block执行完。所以这个时候就出现了strongSelf
,即建立一个__strong
关键字修饰的临时变量,strongSelf
会对weakSelf
指向的self
做retain操作,保证在block执行过程中self
不会被释放。
不过还有一点需要注意的是,weakSelf
可能在block执行开始前就已经释放掉了,这样在block执行时,strongSelf
的值也可能为nil
,所以block中最好还是加上if (strongSelf)
的判断。
疑问
这里有个疑问,strongSelf
在这里又强引用了self
,这样是不是又发生了循环引用呢?
答案是没有循环引用,因为strongSelf
是一个临时变量,即局部变量,这个局部变量在block执行完毕后就释放掉了,这样对self
的强引用也自然就没有了。
网友评论