Weak-Strong-Dance 真的安全吗?

绝大多数iOS开发者用过block,并且知道用 __weak 的方式去解决循环引用的问题。而进阶一些的开发者则了解Weak-Strong-Dance,那么什么是Weak-Strong-Dance?它能保证block执行是的“安全”吗?

1857952-d1a254bf05662388

Weak-Strong-Dance

看看下面两段代码的区别,你就明白什么是Weak-Strong-Dance了。

也就是在用 __weak 解决循环引用的前提下 ,在block内部用 __strong 持有对象,试图解决“在多线程下,可能weakSelf指向的对象会在 Block 执行前被废弃,导致各种各样的问题,比如说KVO,传入nil可是会crash呢”,如下代码

此时,你可能会这样认为,self 所指向对象的引用计数变成 2,即使主线程中的 self 因为超出作用于而释放,对象的引用计数依然为 1,避免了对象的销毁。

思维纠正

它真的能解决在多线程下,可能 weakSelf 指向的对象会在 Block 执行前被废弃而导致的问题吗?
答案当然是否定的,让我们来看看demo:

不用Weak-Strong-Dance

看看用clang改写后的代码,这里就只贴关键代码了:

代码很长,解释下:
struct __TestBlock__test_block_impl_0里头,我们能看到TestBlock *const __weak weakSelf;这代表在 block 内部是以弱引用的方式捕获 self 的,这没毛病。重点来了,看这一段代表 block 具体实现的代码块

这里可以看到如果此时外部废弃了self,的确会导致 block 内部访问成nil的情况。

那么如果用了Weak-Strong-Dance呢?

看看clang改写后会有什么区别:

holy shit!

区别在于在 block 内多了这么一行代码__attribute__((objc_ownership(strong))) typeof(self) strongSelf = weakSelf;

所以持有 self 的行为是在 block 执行的时候才发生的!

回过头来看看问题:它真的能解决在多线程下,可能 weakSelf 指向的对象会在 Block 执行前被废弃而导致的问题吗?

在执行前就废弃,到了执行的时候,weakSelf 已经是 nil 了,此时执行 __strong typeof(self) strongSelf = weakSelf;根本没意义吧。

所以在刚才KVO的例子中,该crash还是继续crash吧。只要在执行__strong typeof(self) strongSelf = weakSelf;前,对象在其他线程被废弃了,Weak-Strong-Dance不能帮上任何忙!

总结

Weak-Strong-Dance并不能保证 block所引用对象的释放时机在执行之后, 更安全的做法应该是在 block 内部使用 strongSelf 时进行 nil检测,这样可以避免上述情况。

1 收藏 评论

相关文章

可能感兴趣的话题



直接登录
跳到底部
返回顶部