当外部 obj 指向 nil 的时候,obj 理应被释放,但实际上 blockObj 依然强引用着 obj,obj 其实并没有被真正释放。因此使用 __block
并不能避免循环引用的问题。
但是我们可以通过手动释放 blockObj 的方式来释放 obj,这就需要我们在 block 内部将要退出的时候手动释放掉 blockObj ,如下这种形式
MyObject *obj = [[MyObject alloc]init]; obj.text = @"11111111111111"; TLog(@"obj",obj); __block MyObject *blockObj = obj; obj = nil; void(^testBlock)() = ^(){ TLog(@"blockObj - block",blockObj); blockObj = nil; }; obj = nil; testBlock(); TLog(@"blockObj",blockObj); |
这种形式既能保证在 block 内部能够访问到 obj,又可以避免循环引用的问题,但是这种方法也不是完美的,其存在下面几个问题
- 必须记住在 block 底部释放掉 block 变量,这其实跟 MRC 的形式有些类似了,不太适合 ARC
- 当在 block 外部修改了 blockObj 时,block 内部的值也会改变,反之在 block 内部修改 blockObj 在外部再使用时值也会改变。这就需要在写代码时注意这个特性可能会带来的一些隐患
__block
其实提升了变量的作用域,在 block 内外访问的都是同一个 blockObj 可能会造成一些隐患
总结
__weak
本身是可以避免循环引用的问题的,但是其会导致外部对象释放了之后,block 内部也访问不到这个对象的问题,我们可以通过在 block 内部声明一个 __strong
的变量来指向 weakObj,使外部对象既能在 block 内部保持住,又能避免循环引用的问题。
__block
本身无法避免循环引用的问题,但是我们可以通过在 block 内部手动把 blockObj 赋值为 nil 的方式来避免循环引用的问题。另外一点就是 __block
修饰的变量在 block 内外都是唯一的,要注意这个特性可能带来的隐患。