這個問題在我做火柴盒用戶crash分析的時候,曾經(jīng)困擾我挺久的,需要較大的用戶量,才能發(fā)現(xiàn)這個crash,解決之后,也不知道怎么敘述出來,恰好最近好幾個人都遇到這個問題了,我在群里裝完逼之后,素顏大大簡單粗暴的給這篇博客起了這個名字,于是就有了這篇博客。

那么,先來個我畫的示意圖:

正文來啦:
一般我們的刷新控件,和網(wǎng)絡(luò)請求數(shù)據(jù)源,刷新界面,是分開來封裝的,而刷新控件往往都會有個動畫,約0.3-0.5s位移向上消失??粗蠄D,如果刷新控件向上運(yùn)動過程中,紫色cell的數(shù)據(jù)源已經(jīng)被更新,木有了,紫色cell繪制的時候,就會出現(xiàn)數(shù)組越界的問題。
出現(xiàn)問題的代碼大概長這樣:
//網(wǎng)絡(luò)請求結(jié)束后,dataArrary已經(jīng)改變后:
[self.tableView.header endRefreshing];//刷新控件恢復(fù)
[self.tableView reloadData];//重繪tableView
最初我的解決方法是:
[self.tableView reloadData];//重繪tableView
// 主線程延遲執(zhí)行:
double delayInSeconds = 0.1f;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[self.tableView.header endRefreshing];//刷新控件恢復(fù)
});
而在昨天和素顏大大討論之后,我今天測試的時候發(fā)現(xiàn),reloadData這個方法,調(diào)用dataSource的時候是同步的,而delegate是異步的。
所以最終解決方法其實很簡單了,先reloadData,再取消刷新控件:
[self.tableView reloadData];//重繪tableView
[self.tableView.header endRefreshing];//刷新控件恢復(fù)
引申一下:
其實在看sunny的UITableView-FDTemplateLayoutCell這個的時候,應(yīng)該就能發(fā)現(xiàn)reloadData調(diào)用dataSource的時候是同步的,為此這個庫做了cell高度的緩存,保證了tableview reloadData時的流暢。
引申第二下:
經(jīng)過素顏大大提醒,MJRefresh對endRefreshing方法采用了0.1秒延時:
#pragma mark - 公共方法
- (void)endRefreshing
{
if ([self.scrollView isKindOfClass:[UICollectionView class]]) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[super endRefreshing];
});
} else {
[super endRefreshing];
}
}
這樣處理面對固定高度的cell,不會產(chǎn)生問題,但是,如果高度需要非常復(fù)雜的計算,或者是xib的高度獲取,線程block時間要長于0.1s,仍然會出現(xiàn)問題。
寫在最后:
技術(shù)這種東西,真是越研究,越發(fā)現(xiàn)自己懂得太少,很多東西看過,就忘了,最簡單的東西,也需要融會貫通?,F(xiàn)在看看我之前解決本文問題的延時辦法,真是蠢哭了。。
寫代碼的時候,實現(xiàn)效果是最低級的,更多時間要在想,為什么這么做,有沒有更好的方法,還有其他的優(yōu)化空間么?與大家共勉。
簡書已經(jīng)棄用,歡迎移步我的小專欄:
https://xiaozhuanlan.com/dahuihuiiOS