一. 问题背景
项目中遇到一个问题,就是当App
不在首页的时候,切换到其他App
比如微信,然后返回App
当前页面,然后从当前页面返回首页,会在首页viewWillAppear
这里去拉取是否有未完成订单的接口,刷新UITableView
,这时会出现广告位闪烁问题。
二. 问题排查
1.原因分析
这个问题经过断点调试和排除法,发现只要当App
进入后台后,回来刷新首页的UITableView
都有可能出现闪烁现象。
因此首先我们对图片的加载做延迟操作,并在Cell
生成方法调用里面添加相关打印:
可以看到如下打印日志:
-------------------------indexPath:[0, 0] cell:<XXXTableViewCell: 0x144023800; baseClass = UITableViewCell; frame = (0 36; 414 111); hidden = YES; autoresize = W; backgroundColor = UIExtendedGrayColorSpace 0 0; layer = <CALayer: 0x2823b2f20>>
-------------------------indexPath:[0, 1] cell:<XXXTableViewCell: 0x144891c00; baseClass = UITableViewCell; frame = (0 147; 414 111); hidden = YES; autoresize = W; backgroundColor = UIExtendedGrayColorSpace 0 0; layer = <CALayer: 0x282392ac0>>
-------------------------indexPath:[0, 2] cell:<XXXTableViewCell: 0x144069000; baseClass = UITableViewCell; frame = (0 258; 414 111); hidden = YES; autoresize = W; backgroundColor = UIExtendedGrayColorSpace 0 0; layer = <CALayer: 0x2823b3d40>>
-------------------------indexPath:[0, 3] cell:<XXXTableViewCell: 0x144863c00; baseClass = UITableViewCell; frame = (0 369; 414 111); hidden = YES; autoresize = W; backgroundColor = UIExtendedGrayColorSpace 0 0; layer = <CALayer: 0x282393a80>>
-------------------------调用self.contentTableView.reloadData
-------------------------indexPath:[0, 0] cell:<XXXTableViewCell: 0x144863c00; baseClass = UITableViewCell; frame = (0 369; 414 111); hidden = YES; autoresize = W; backgroundColor = UIExtendedGrayColorSpace 0 0; layer = <CALayer: 0x282393a80>>
-------------------------indexPath:[0, 1] cell:<XXXTableViewCell: 0x144069000; baseClass = UITableViewCell; frame = (0 258; 414 111); hidden = YES; autoresize = W; backgroundColor = UIExtendedGrayColorSpace 0 0; layer = <CALayer: 0x2823b3d40>>
-------------------------indexPath:[0, 2] cell:<XXXTableViewCell: 0x144891c00; baseClass = UITableViewCell; frame = (0 147; 414 111); hidden = YES; autoresize = W; backgroundColor = UIExtendedGrayColorSpace 0 0; layer = <CALayer: 0x282392ac0>>
-------------------------indexPath:[0, 3] cell:<XXXTableViewCell: 0x144023800; baseClass = UITableViewCell; frame = (0 36; 414 111); hidden = YES; autoresize = W; backgroundColor = UIExtendedGrayColorSpace 0 0; layer = <CALayer: 0x2823b2f20>>
从打印日志我们可以看出来,调用reloadData
方法后,原来UITableView
的cell
位置会调整。
但是如果我们App
没有进入后台,而是直接调用UITableView
的reloadData
方法,并不会出现闪烁现象。
因此可以这里可以推测应该是进入后台做了什么操作导致,回到App
刷新才会导致闪烁。
因为使用的是SDWebImage
加载框架加载,我们合理的怀疑是加载图片的SDWebImage
框架,进入后台的处理逻辑导致的,因此我们先使用imageCacheDict字典
写下图片加载和缓存逻辑:
经测试,进入后台,再返回App
刷新不会出现闪烁现象。
因此可以肯定UITableView
调用reloadData
方法闪烁原因是SDWebImage
,在进入后台的时候对内存缓存做了相关操作导致。
我们都知道SDWebImage
,默认是使用NSCache
来做内存缓存,而NSCache
在进入后台的时候,默认会清空缓存操作,导致返回App
调用UITableView
调用reloadData
方法时候,SDWebImage
需要根据图片地址重新去磁盘获取图像数据,然后解压解码渲染,因为是从缓存磁盘直接获取图像数据,没有渲染流程,因此会造成闪烁。
为了验证这个猜想,我们使用YYWebImage
加载框架来做对比实验:
- 首先注释掉
YYWebImage
进入后台清空内存缓存的逻辑:
- 然后进入后台,返回
App
调用UITableView
调用reloadData
刷新,发现一切正常。
-
原因总结:
第一个原因是
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];
}