为什么在 SDWebImage "strong reference to UIImageView might cause a crash in the nested block" 中?

Why in SDWebImage "strong reference to UIImageView might cause a crash in the nested block"?

我使用的是旧版本的 SDWebImage,但遇到如下崩溃:

0   libobjc.A.dylib                     0x000000019671bbd0 objc_msgSend + 16
1   UIKit                               0x0000000189932eac -[UIView(Rendering) contentMode] + 316
2   UIKit                               0x00000001899320e0 -[UIImageView _canDrawContent] + 144
3   UIKit                               0x0000000189932bac -[UIImageView _updateState] + 36
4   UIKit                               0x0000000189932b6c +[UIView(Animation) performWithoutAnimation:] + 88
5   UIKit                               0x0000000189c6b340 -[UIImageView _updateImageViewForOldImage:newImage:] + 452
6   UIKit                               0x0000000189932590 -[UIImageView setImage:] + 320
7   xxxx                                0x0000000100927adc __85-[UIImageView(WebCache) setImageWithURL:placeholderImage:options:progress:completed:]_block_invoke + 100

发生崩溃的区块是:

        __weak UIImageView *wself = self;
    id<SDWebImageOperation> operation = [SDWebImageManager.sharedManager downloadWithURL:url options:options progress:progressBlock completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished)
                                         {
                                             __strong UIImageView *sself = wself;
                                             if (!sself) return;
                                             if (image)
                                             {
                                                 sself.image = image;
                                                 [sself setNeedsDisplay];
                                                 [sself setNeedsLayout];
                                             }
                                             if (completedBlock && finished)
                                             {
                                                 completedBlock(image, error, cacheType);
                                             }
                                         }];

然后我找到了一个SDWebImage的修复,提交评论是:

Removed strong reference to UIImageView which was causing a crash in the nested block

这里是commit。唯一的变化是删除块中 UIImageView 的强引用。

在块中使用强引用来保持一致性被广泛使用,但为什么SDWebImage会有这样的变化。为什么这会导致崩溃?如果 UIImageView 会导致崩溃,还有什么会?

该修复程序可以解决的是视图删除期间的竞争条件 and/or 销毁,其中正在释放内部渲染缓冲区,但可以及时应用保留以防止释放。然后,如果有什么东西触发写入那些现在消失的缓冲区,你就会得到那个分段错误。

理论上,直接访问原始指针且未充分保护其销毁的任何地方都可能遇到此问题。实际上,除了基于 UIImage 的 API 之外,UIKit 级别的代码不太可能 运行 进入其中,我想这将是一个相当深奥的竞争条件,在视图拆卸之前小心取消所有异步更新开始应该彻底消除;无论如何,您应该这样做以避免不必要的工作。