主队列dispatch_async内weakSelf是否始终有效?仅非主队列需声明strongSelf?
咱们先把两个问题拆开来逐个说清楚:
一、主队列里的weakSelf并非始终可用/有效
你可能觉得主队列是串行的,block会按顺序执行,就以为self肯定还在,但其实不是这样的。dispatch_async(dispatch_get_main_queue(), ^{...})是异步派发任务到主队列,这个block会排在主队列的任务末尾等待执行。
举个场景:假设这段代码是在一个MyView实例的方法里,而在这个block被主队列调度执行之前,外界已经把这个MyView实例释放了(比如它所在的控制器被pop,或者父视图把它移除并释放),那weakSelf就会自动变成nil——主队列没法保证self在block执行时一定存活,因为异步派发的block和当前线程的代码(或者其他线程操作self的代码)是可能并发的。
哪怕当前代码是在主线程执行的,当前代码执行完才会轮到block,但如果在当前代码执行完到block开始执行的间隙,self被其他逻辑释放了,weakSelf照样会变成nil。
二、不是只有非主队列才需要声明strongSelf
很多人误以为strongSelf只是非主队列的专属,其实完全不是。strongSelf的核心作用是在block执行期间临时持有self:
- 避免block执行过程中self突然被释放,导致后续访问属性/方法时出现不可预料的问题;
- 避免多次判断weakSelf是否为nil的冗余操作,让逻辑更连贯。
不管是主队列还是非主队列的block,只要你需要在block里连续调用self的多个方法、访问多个属性,都建议先把weakSelf赋值给strongSelf,做非空判断后再执行逻辑。比如你的代码可以优化成这样:
__weak MyView *weakSelf = self; dispatch_async(dispatch_get_main_queue(), ^{ __strong MyView *strongSelf = weakSelf; if (!strongSelf) return; [strongSelf.activityIndicatorView stopAnimating]; [strongSelf.activityIndicatorView removeFromSuperview]; strongSelf.activityIndicatorView = nil; });
这样做的好处很明显:如果strongSelf不为nil,那整个block执行期间self都会被持有,不会出现执行到一半self被释放的情况;如果weakSelf已经是nil,直接return就能避免无效操作,逻辑更严谨。
哪怕是主队列的block,这么写也能让你的代码更健壮,避免潜在的崩溃或逻辑异常。
内容的提问来源于stack exchange,提问作者srus2017

