一. 问题布景

项目中遇到一个问题,就是当App不在主页的时分,切换到其他App比方微信,然后回来App当时页面,然后从当时页面回来主页,会在主页viewWillAppear这儿去拉取是否有未完成订单的接口,改写UITableView,这时会呈现广告位闪耀问题。

iOS UITableView 图片刷新闪烁问题记录

二. 问题排查

1.原因剖析

这个问题经过断点调试和排除法,发现只需当App进入后台后,回来改写主页的UITableView都有或许呈现闪耀现象。

因而首要咱们对图片的加载做推迟操作,并在Cell生成办法调用里边增加相关打印:

iOS UITableView 图片刷新闪烁问题记录

iOS UITableView 图片刷新闪烁问题记录

能够看到如下打印日志:

iOS UITableView 图片刷新闪烁问题记录

从打印日志咱们能够看出来,调用reloadData办法后,本来UITableViewcell位置会调整。

但是假如咱们App没有进入后台,而是直接调用UITableViewreloadData办法,并不会呈现闪耀现象。

因而能够这儿能够估测应该是进入后台做了什么操作导致,回到App改写才会导致闪耀。

因为运用的是SDWebImage加载结构加载,咱们合理的怀疑是加载图片的SDWebImage结构,进入后台的处理逻辑导致的,因而咱们先运用imageCacheDict字典写下图片加载和缓存逻辑:

iOS UITableView 图片刷新闪烁问题记录

经测试,进入后台,再回来App改写不会呈现闪耀现象。

因而能够必定UITableView调用reloadData办法闪耀原因是SDWebImage,在进入后台的时分对内存缓存做了相关操作导致。

咱们都知道SDWebImage,默许是运用NSCache来做内存缓存,而NSCache在进入后台的时分,默许会清空缓存操作,导致回来App调用UITableView调用reloadData办法时分,SDWebImage需要依据图片地址从头去磁盘获取图画数据,然后解压解码烘托,因为是从缓存磁盘直接获取图画数据,没有烘托流程,因而会形成闪耀。

为了验证这个猜想,咱们运用YYWebImage加载结构来做对比实验:

  • 首要注释掉YYWebImage进入后台清空内存缓存的逻辑:
    iOS UITableView 图片刷新闪烁问题记录

iOS UITableView 图片刷新闪烁问题记录

  • 然后进入后台,回来App调用UITableView调用reloadData改写,发现一切正常。
  1. 原因总结:

  • 第一个原因是UITableView调用reloadData办法,因为UITableViewCell的复用,会呈现Cell位置调整现象

  • 因为SDWebImage运用了NSCache做内存缓存,当App进入后台,NSCache会清空内存缓存,导致回来App后调用UITableView调用reloadData,改写去加载图片的时分,需要从SDWebImage的磁盘中从头获取图片数据,然后从头解压解码烘托,因为从磁盘中读取速度快,两者原因导致了闪耀。

三. 解决方案

因为该现象是由如上两个原因导致,因而针对这两个原因,有如下两种解决方案:

  • 解决UITableViewCell复用问题

能够经过设置ReusableCellWithIdentifier不同,保证广告cell不进行复用。

 NSString *cellId = [NSString stringWithFormat:@"%ld-%ld-FJFAdTableViewCell", indexPath.section, indexPath.row];
  • 从后台回来后,提前进行改写操作

当从后台回来App前台的时分或许视图增加到父视图的时分,先履行下UITableView调用reloadData办法,提前经过SDWebImage去从磁盘中加载图片。

从后台回来前台:

[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(willEnterForeground) name:UIApplicationWillEnterForegroundNotification object:nil];
- (void)willEnterForeground {
    [self.tableView reloadData];
    NSLog(@"--------------------------willEnterForeground");
}

视图增加到父视图:

- (void)willMoveToParentViewController:(UIViewController *)parent {
    [self.tableView reloadData];
}