在同一個(gè) UITableView 中顯示不同樣式的復(fù)雜 Cell 時(shí)胆数,必然會遇到這么一個(gè)問題:雖然有重用機(jī)制,但在首次創(chuàng)建的時(shí)候互墓,還是會消耗不少cpu時(shí)間必尼,造成卡頓。
舉個(gè)例子:UITableView 有兩類Cell,初始顯示A類判莉,那么切換到B類的時(shí)候豆挽,就必定要?jiǎng)?chuàng)建B類Cell,造成卡頓券盅,雖然創(chuàng)建完之后就沒有卡頓問題了(前提是做好一系列其它的優(yōu)化)帮哈,但還是有點(diǎn)不爽,那么該怎么解決這個(gè)問題呢渗饮?
我想到3個(gè)方案:
- AsyncDisplayKit,這個(gè)之前使用過但汞,雖然沒有卡頓,但是UI的展示會有延遲互站,有些本來不會卡頓的場景也會有UI延遲的問題私蕾,有它的使用場景,但放到這里來胡桃,感覺并不是完美的方案踩叭,而且有種殺雞用牛刀的感覺。
- 在同一種 Cell 中通過隱藏部分UI元素避免額外的新建翠胰,這種方案的弊端是Cell類實(shí)現(xiàn)起來必定巨大不堪容贝,難以維護(hù),相比得到的好處之景,弊多利少斤富。
- 提前創(chuàng)建好足夠使用的 Cell 緩存池,然后在要使用的地方先從自己之前創(chuàng)建好的地方去取锻狗,這樣其實(shí)是將創(chuàng)建提前满力,雖然開始時(shí)加載時(shí)間延長了,但是使用時(shí)候就不會有卡頓了轻纪。而且修改量也小油额,實(shí)現(xiàn)起來比較容易。
取第三種方案刻帚,看代碼潦嘶,實(shí)現(xiàn)起來還是稍微有一些注意點(diǎn)的:
···
// p_speedUpCellCreate 函數(shù),每種Cell要?jiǎng)?chuàng)建的數(shù)量可以根據(jù)不同類型Cell的高度和手機(jī)型號預(yù)估崇众,太少則不夠掂僵,太多則太耗時(shí)
// 因?yàn)槭褂昧?FDTemplateLayoutCell 在計(jì)算高度的時(shí)候會私藏一份,所以提前調(diào)用創(chuàng)建
[self.tableView fd_heightForCellWithIdentifier:kIdentifierA configuration:nil];
[self.tableView fd_heightForCellWithIdentifier:kIdentifierB configuration:nil];
// 不能直接new顷歌,需要指定重用標(biāo)識符
UITableViewCellA* cellA = [[UITableViewCellA alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kIdentifierA];
// 因?yàn)槭褂昧?MGSwipeButton 看峻,所以要提前創(chuàng)建,每次僅更新 Buttons衙吩,不創(chuàng)建新的 Button
cell.rightButtons = [self p_configCellRightButtons:0 buttons:[cell.rightButtons mutableCopy]];
// 存起來
[self.cellSpeedUp[kIdentifierA] addObject: cellA];
...
UITableViewCellB* CellB = .....
然后在 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRow:(NSInteger)row 中
UITableViewCell* cell = nil;
if (self.cellSpeedUp[kIdentifierA].count > 0) {
cell = self.cellSpeedUp[kIdentifierA][0];
[self.cellSpeedUp[kIdentifierA]] removeObjectAtIndex:0];
}
else
{
cell = [tableView dequeueReusableCellWithIdentifier: kIdentifierA];
}
···
然后將p_speedUpCellCreate 放到合適的地方去調(diào)用就行了,當(dāng)然必須放在主線程溪窒。
2018-04-04 更新
隨著需求的發(fā)展坤塞,逐漸出現(xiàn)新的隱患:隨著cell種類的增多冯勉,緩存池創(chuàng)建的時(shí)間也逐漸增多,比如原來3種摹芙,每種創(chuàng)建6個(gè)灼狰,那就是18個(gè),如果種類增加到10種浮禾,緩存池的數(shù)量劇增到60個(gè)交胚。雖然目前耗時(shí)不太明顯,但可以預(yù)見到的是早晚有一天時(shí)間會不可接受盈电。那么蝴簇,如何優(yōu)化呢?
思路1
能不能將創(chuàng)建時(shí)間從啟動(dòng)延遲到啟動(dòng)后匆帚?
嘗試了一下熬词,利用GCD的異步低優(yōu)先級隊(duì)列,將創(chuàng)建延遲到了啟動(dòng)完成后吸重,實(shí)際效果為啟動(dòng)變快了互拾,但會有短暫的界面無響應(yīng)情況存在(主線程正在創(chuàng)建cell)。配合頁面下拉刷新的動(dòng)畫嚎幸,貌似能接受颜矿。
但總還是不完美,是吧嫉晶?
思路2
其實(shí)問題在于創(chuàng)建了太多用不著的cell骑疆,可能實(shí)際用戶只有一種cell,那么其實(shí)就是做了很多多余的動(dòng)作车遂,想到這一點(diǎn)封断,就有辦法了。
理想的解決方案是后臺提供一個(gè)接口舶担,返回各種 數(shù)據(jù)的數(shù)量(如果有分頁坡疼,只需第一頁的數(shù)量即可),按照這個(gè)數(shù)量進(jìn)行緩存池的創(chuàng)建即可衣陶。
不依賴后臺的情況下柄瑰,可以在每次拉取數(shù)據(jù)之后,將各種類型的數(shù)量進(jìn)行緩存剪况,下次啟動(dòng)時(shí)教沾,根據(jù)不同類型不同分類計(jì)算恰當(dāng)?shù)木彺鏀?shù)量。
補(bǔ)充優(yōu)化
進(jìn)一步還可以根據(jù)不同機(jī)型 译断,不同類別的cell授翻,設(shè)置預(yù)估單屏數(shù)量,如果cell高度比較高,可能兩三個(gè)就夠了堪唐,如果高度比較低巡语,那么需要多一點(diǎn)。
后記
經(jīng)過這些優(yōu)化淮菠,可以將cell緩存池單來的副作用降低到最低男公,后期將不會產(chǎn)生cell種類增多帶來啟動(dòng)時(shí)間增加的影響。