UICollectionView 图片闪烁


  前两天测试提了一个问题,不方便发图片和视频,那先简单描述一下 App 构造:App 是类似钉钉的一个办公软件,首页也是类似钉钉「办公专区」的页面。测试反馈从后台回到前台时,只要 Tab 切换到首页,首页中 UICollectionView 的部分图标就一定会闪一下;如果在前台切换 Tab 页签的话,偶尔能复现…

  用了这么久的 UICollectionView,我也是第一次遇到这种情况,一开始甚至把锅丢给了苹果,不禁感叹了一下苹果系统做的越来越不稳定🤓;没办法,这种甩锅的行为也不是咱的作风,开始解决吧:
  看到很多网友都在讨论 UICollectionViewCell 闪烁的问题,把解决问题的方向也定在了这里,针对 UICollectionView 的 reload 时机、频率、Cell 复用机制、切换多线程,各种方案尝试了一个遍,历经两天一晚的时间,我成功把它改的每一次都闪烁了呢,真棒😂……图标闪烁的速度也是相当快,快到肉眼看不清,突然想起来录个屏、自己不停的回放、慢放、来回拖拽进度条…终于找到了元凶 – SDWebImage,闪烁的图标会先展示目标图片、又展示了一次占位图、又展示了一次目标图片,占位图是一个空位图,所以视觉上看到的是闪烁一下。

-->
-->

关于 UICollectionView 闪烁的问题,印象中看的几篇文章,有兴趣的自己看吧,我不想转载了,看到它们头疼:

1
2
3
4
https://stackoverflow.com/questions/23740782/uicollectionview-reloaddata-but-view-blinks
https://blog.csdn.net/u013712343/article/details/126748755
https://maweefeng.github.io/15766567217978.html
https://www.jianshu.com/p/94f3912c3e8a

关于使用 SDWebImage 闪烁的问题,其实 SDK 中已经给出了解决方案:

1
2
3
4
5
6
/**
* By default, when the memory cache miss, we query the disk cache asynchronously. This mask can force to query disk cache (when memory cache miss) synchronously.
* @note These 3 query options can be combined together. For the full list about these masks combination, see wiki page.
* @note Query data synchronously is not recommend, unless you want to ensure the image is loaded in the same runloop to avoid flashing during cell reusing.
*/
SDWebImageQueryDiskDataSync = 1 << 14,

@note Query data synchronously is not recommend, unless you want to ensure the image is loaded in the same runloop to avoid flashing during cell reusing.

SDK 中已经给出了非常明确的注释,一开始的方向完全是错误的。哭笑不得,时间都浪费了,所以一定要先搞清楚问题的本质是什么,谋定而后动,而且怎么把内功心法忘了呢:RTFSC - Read the fucking source code.


SDWebImageOptions 的注释翻译:

SDWebImageOptions 注释翻译
Option 注释
SDWebImageRetryFailed 一般情况下,一个URL下载失败后会被加入黑名单组织下次下载,如果设置了这个option,则不会加入黑名单。
SDWebImageLowPriority 默认情况下图片会在交互发生时开始下载,设置了这个option图片就会延迟下载,例如滑动 TableView 时,会在 scrollview 减速时才开始下载。
SDWebImageProgressiveLoad 这个option是启用了渐进式下载,像网页加载一样一点一点显示。默认情况下,一次显示完全下载的图片。
SDWebImageRefreshCached 对缓存进行刷新。
SDWebImageContinueInBackground 后台继续下载。
SDWebImageHandleCookies 通过设置 NSMutableURLRequest.HTTPShouldHandleCookies = YES; 处理 Cookie。
SDWebImageAllowInvalidSSLCertificates 允许使用不受信任的SSL证书,一般用于测试。
SDWebImageHighPriority 默认情况下,图片按照他们加载下载队列中的顺序下载,这个 option 提高下载优先级。
SDWebImageDelayPlaceholder 默认情况下,图片开始加载就显示默认图片,这个 option 延迟了默认图的显示知道图片加载完成。
SDWebImageTransformAnimatedImage 通常情况下我们不会对下载的图片进行变换,因为可能对图片造成损伤,这个 option 可以让我们对图片进行任意变换。
SDWebImageAvoidAutoSetImage 默认情况下,图片在下载后被自动添加到imageView上。这个 option 可以让我们手动添加图片到 imageView 上。
SDWebImageScaleDownLargeImages 当下载的图片太大时,允许把它缩小到一个合适的大小再显示。
SDWebImageQueryMemoryData 默认情况下,当image已经缓存到内存中时,不会再查询imageData,这个 option 可以设置同时查询imageData,这个查询是异步的,除非指定'SDWebImageQueryMemoryDataSync'。
SDWebImageQueryMemoryDataSync 默认情况下,当你只指定'SDWebImageQueryMemoryData'时,会异步查询内存imageData。结合此掩码可以同步查询。但不建议同步查询,除非你想确保图像加载在同一个runloop中,以避免单元格重用时闪烁。
SDWebImageQueryDiskDataSync 默认情况下,当内存缓存丢失时,异步查询磁盘缓存。该option可以强制同步查询磁盘缓存。
SDWebImageFromCacheOnly 这个 option 可以设置只允许从缓存中获取图片。
SDWebImageFromLoaderOnly 这个 option 可以设置只允许从加载器加载图片。
SDWebImageForceTransition 默认情况下,当你使用“SDWebImageTransition”在图像加载完成后做一些视图转换时,这个转换只适用于从网络下载的图像。这个option可以强制应用内存和磁盘缓存的视图也转换。
SDWebImageAvoidDecodeImage 默认情况下,我们将在查询缓存或者从网络下载之后直接解码图像。这有助于提高性能,因为在屏幕上呈现图像时,首先需要对其进行解码。但这发生在Core Animation的主队列上。所以,这个进程可能会导致内存使用过大。如果由于内存消耗过多而遇到问题,此option可以阻止对图像进行解码。
SDWebImageDecodeFirstFrameOnly 默认情况下,会对动图进行解码。这个option强制只解码第一帧并产生静态图像。
SDWebImagePreloadAllFrames 默认情况下,对于SDAnimatedImage,是在渲染过程中解码动画图像帧以减少内存使用。但是,当动画图像被许多imageViews共享时,可以指定将动图所有帧预加载到内存中,以减少CPU占用。
SDWebImageMatchAnimatedImageClass 使用这个option,可以确保按照用户提供的类回调相应图像。如果无法生成,则会使用代码“SDWebImageErrorBadImageData”的错误。
SDWebImageWaitStoreCache 等待图片写入缓存完成再回调。
SDWebImageTransformVectorImage 一般情况下不会对矢量图像做变换,因为矢量图像在做变换时会丢失细节。这个option 可以随意转换矢量图。