一. 問題背景
項目中遇到一個問題,就是當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
進入后臺清空內存緩存的邏輯:
image.png
- 然后進入后臺,返回
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];
}