1-1. Cell重用
在可見頁面每次刷新顯示都會去創(chuàng)建新的Cell?
答:不是捉兴,這樣非常耗費性能蝎困。
解決方案:
- static NSString *reuseID = “reuseCellID”; //代理方法返回Cell會調(diào)用很多次,防止重復創(chuàng)建倍啥,static保證只會被創(chuàng)建一次禾乘,提高性能
- UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseID];//從緩存池中取相應identifier的Cell并更新數(shù)據(jù),如果沒有虽缕,才開始alloc新的Cell始藕,并用identifier標識Cell。每個Cell都會注冊一個identifier(重用標識符)放入緩存池氮趋,當需要調(diào)用的時候就直接從緩存池里找對應的id伍派,當不需要時就放入緩存池等待調(diào)用。
備注:移出屏幕的Cell不會被release剩胁,會放入緩存池中诉植。
1-2. 緩存池
UITableView什么時候開辟內(nèi)存給Cell?
答:當Cell執(zhí)行alloc時,UITableView會在堆中開辟一段內(nèi)存以供Cell緩存之用昵观。
緩存池會緩存所有Cell嗎晾腔?
答:緩存池中只會保存已經(jīng)被移出屏幕的不同類型的Cell舌稀。
Cell的重用通過identifier標識,緩存池是否一可變字典建车?
答:可能是扩借,因為原理與字典相似,字典用key, cell重用以identifier缤至。
Cell的類型多種多樣潮罪,緩存池字典內(nèi)部是什么呢?
答:可能是可變數(shù)組领斥,也可能是可變的Set集合嫉到,因為只有數(shù)組,Set都可以存放不同高度月洛、不同類型(包含圖片何恶、Label等)的Cell。Set還有存放數(shù)據(jù)的唯一性嚼黔。
1-3. 緩存池獲取可重用Cell兩個方法的區(qū)別
第一種方式:
-(nullable __kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier;
附上示例:
cell = [self.tableView dequeueReusableCellWithIdentifier:kDisplayCell_ID];
if(cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kDisplayCell_ID]];
}
這個方法會查詢可重用Cell细层,如果注冊了原型Cell,能夠查詢到唬涧,否則疫赎,返回nil;而且需要判斷if(cell == nil)碎节,才會創(chuàng)建Cell捧搞,不推薦
第二種方式:
-(__kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(6_0);
這種方法,必須注冊Cell;
方法: 通過xib(storyboard)或是Class(純代碼)注冊可重用Cell(這個方法一定會返回一個Cell)
共2種注冊Cell的方式:
registerNib---> - (void)registerNib:(nullable UINib *)nib forCellReuseIdentifier:(NSString *)identifier NS_AVAILABLE_IOS(5_0);
registerClass---> - (void)registerClass:(nullable Class)cellClass forCellReuseIdentifier:(NSString *)identifier NS_AVAILABLE_IOS(6_0);
相比于第一種方式狮荔,第二種的優(yōu)勢在于:如果緩沖區(qū) Cell 不存在胎撇,會使用原型 Cell 實例化一個新的 Cell,不需要再判斷殖氏,同時代碼結(jié)構(gòu)更清晰晚树。定義一種(盡量少)類型的Cell及善用hidden隱藏(顯示)subviews
2-1. 一種類型的Cell
分析Cell結(jié)構(gòu),盡可能的將 相同內(nèi)容的抽取到一種樣式Cell中雅采,前面已經(jīng)提到了Cell的重用機制爵憎,這樣就能保證UITbaleView要顯示多少內(nèi)容,真正創(chuàng)建出的Cell可能只比屏幕顯示的Cell多一點总滩。雖然Cell的’體積’可能會大點纲堵,但是因為Cell的數(shù)量不會很多,完全可以接受的闰渔。好處:
減少代碼量席函,減少Nib文件的數(shù)量,統(tǒng)一一個Nib文件定義Cell冈涧,容易修改茂附、維護
基于Cell的重用正蛙,真正運行時鋪滿屏幕所需的Cell數(shù)量大致是固定的,設為N個营曼。如果只有一種Cell乒验,那就是只有N個Cell的實例;但是如果有M種Cell蒂阱,那么運行時最多可能會是“M x N = MN”個Cell的實例锻全,雖然可能并不會占用太多內(nèi)存,但是能少點不是更好嗎录煤?
2-2. 善用hidden隱藏(顯示)subviews
只定義一種Cell鳄厌,那該如何顯示不同類型的內(nèi)容呢?答案就是妈踊,把所有不同類型的view都定義好了嚎,放在cell里面,通過hidden顯示廊营、隱藏歪泳,來顯示不同類型的內(nèi)容。畢竟露筒,在用戶快速滑動中呐伞,只是單純的顯示、隱藏subview比實時創(chuàng)建要快得多邀窃。
- 提前計算并緩存Cell的高度
在不設UITableViewCell的預估行高的情況下荸哟,會優(yōu)先調(diào)用”tableView:heightForRowAtIndexPath:”方法假哎,獲取每個Cell的即將顯示的高度瞬捕,從而確定UITableView的布局,實際就是要獲取contentSize(UITableView繼承自UIScrollView,只有獲取滾動區(qū)域舵抹,才能實現(xiàn)滾動),然后才調(diào)用”tableView:cellForRowAtIndexPath”,獲取每個Cell肪虎,進行賦值。如果項目中模塊有10000個Cell需要顯示惧蛹,可想而知…
解決方案:使用MVVM扇救,將計算Cell高度放入ViewModel(視圖模型)中,讓Model(數(shù)據(jù)模型)只負責處理數(shù)據(jù)香嗓。
ViewModel:
TableView:
運行結(jié)果:
4.異步繪制(自定義Cell繪制)
參考這篇文章:
http://www.cocoachina.com/articles/11968
5.滑動時迅腔,按需加載
現(xiàn)在很多自定義的Cell都會附有圖片,在列表下滑加載更多過程中靠娱,如果每個Cell都在加載圖片沧烈,那么會很卡頓!
可能有人會說誰那么傻像云,用異步線程即可锌雀,可是每個都加線程蚂夕,開啟的線程太多,一樣會卡頓腋逆,線程條數(shù)一般3-5條婿牍,最多也就6條。
這時候UIScrollViewDelegate兩個代理方法就能很好地解決這個問題惩歉。
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
思路:識別UITableView禁止或者減速滑動結(jié)束的時候等脂,進行異步加載圖片,快滑動過程中撑蚌,只加載目標范圍內(nèi)的Cell慎菲,這樣按需加載,極大的提高流暢度锨并。而SDWebImage可以實現(xiàn)異步加載露该,與這條性能配合就完美了,尤其是大量圖片展示的時候第煮。而且也不用擔心圖片緩存會造成內(nèi)存警告的問題解幼。
//獲取可見部分的Cell
NSArray *visiblePaths = [self.tableView indexPathsForVisibleRows];
for (NSIndexPath *indexPath in visiblePaths)
{
//獲取的dataSource里面的對象,并且判斷加載完成的不需要再次異步加載
<code>
}
在“tableView:cellForRowAtIndexPath:”方法中加入判斷:
// tableView 停止滑動的時候異步加載圖片
-
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
if (self.tableView.dragging == NO && self.tableView.decelerating == NO) { //開始異步加載圖片 <code> }
6.緩存View
當Cell中的部分View是非常獨立的包警,并且不便于重用的撵摆,而且“體積”非常小,在內(nèi)存可控的前提下害晦,我們完全可以將這些view緩存起來特铝。當然也是緩存在模型中。
7.避免大量的圖片縮放壹瘟、顏色漸變等鲫剿,盡量顯示“大小剛好合適的圖片資源”
8.避免同步的從網(wǎng)絡、文件獲取數(shù)據(jù)稻轨,Cell內(nèi)實現(xiàn)的內(nèi)容來自web灵莲,使用異步加載,緩存請求結(jié)果
9.渲染
9-1. 減少subviews的個數(shù)和層級
子控件的層級越深殴俱,渲染到屏幕上所需要的計算量就越大政冻;如多用drawRect繪制元素,替代用view顯示
9-2. 少用subviews的透明圖層
對于不透明的View线欲,設置opaque為YES明场,這樣在繪制該View時,就不需要考慮被View覆蓋的其他內(nèi)容(盡量設置Cell的view為opaque李丰,避免GPU對Cell下面的內(nèi)容也進行繪制)
9-3. 避免CALayer特效(shadowPath)
給Cell中View加陰影會引起性能問題苦锨,如下面代碼會導致滾動時有明顯的卡頓:
總結(jié):UITableView的優(yōu)化主要從三個方面入手:
提前計算并緩存好高度(布局),因為heightForRowAtIndexPath:是調(diào)用最頻繁的方法;(這個是開發(fā)中肯定會要優(yōu)化的逆屡,不可能一個app就幾個Cell吧)
滑動時按需加載圾旨,防止卡頓,這個我也認為是很有必要做的性能優(yōu)化魏蔗,配合SDWebImage
異步繪制砍的,遇到復雜界面,遇到性能瓶頸時莺治,可能就是突破口(如題廓鞠,遇到復雜的界面,可以從這入手)
緩存一切可以緩存的谣旁,這個在開發(fā)的時候床佳,往往是性能優(yōu)化最多的方向
此文部分引用:https://blog.csdn.net/u011452278/article/details/60961350