iOS --- UITableView性能優(yōu)化

1-1. Cell重用

在可見頁面每次刷新顯示都會去創(chuàng)建新的Cell?

答:不是捉兴,這樣非常耗費性能蝎困。

解決方案:

  1. static NSString *reuseID = “reuseCellID”; //代理方法返回Cell會調(diào)用很多次,防止重復創(chuàng)建倍啥,static保證只會被創(chuàng)建一次禾乘,提高性能
  2. 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的方式:

  1. registerNib---> - (void)registerNib:(nullable UINib *)nib forCellReuseIdentifier:(NSString *)identifier NS_AVAILABLE_IOS(5_0);

  2. registerClass---> - (void)registerClass:(nullable Class)cellClass forCellReuseIdentifier:(NSString *)identifier NS_AVAILABLE_IOS(6_0);
    相比于第一種方式狮荔,第二種的優(yōu)勢在于:如果緩沖區(qū) Cell 不存在胎撇,會使用原型 Cell 實例化一個新的 Cell,不需要再判斷殖氏,同時代碼結(jié)構(gòu)更清晰晚树。

  3. 定義一種(盡量少)類型的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)建要快得多邀窃。

  1. 提前計算并緩存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:


image.png

TableView:


image.png

運行結(jié)果:


image.png

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加陰影會引起性能問題苦锨,如下面代碼會導致滾動時有明顯的卡頓:
image.png

總結(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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市榄审,隨后出現(xiàn)的幾起案子砌们,更是在濱河造成了極大的恐慌,老刑警劉巖搁进,帶你破解...
    沈念sama閱讀 222,807評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件浪感,死亡現(xiàn)場離奇詭異,居然都是意外死亡饼问,警方通過查閱死者的電腦和手機影兽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,284評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來莱革,“玉大人峻堰,你說我怎么就攤上這事≈咽樱” “怎么了捐名?”我有些...
    開封第一講書人閱讀 169,589評論 0 363
  • 文/不壞的土叔 我叫張陵,是天一觀的道長左冬。 經(jīng)常有香客問我桐筏,道長纸型,這世上最難降的妖魔是什么拇砰? 我笑而不...
    開封第一講書人閱讀 60,188評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮狰腌,結(jié)果婚禮上除破,老公的妹妹穿的比我還像新娘。我一直安慰自己琼腔,他們只是感情好瑰枫,可當我...
    茶點故事閱讀 69,185評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般光坝。 火紅的嫁衣襯著肌膚如雪尸诽。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,785評論 1 314
  • 那天盯另,我揣著相機與錄音性含,去河邊找鬼。 笑死鸳惯,一個胖子當著我的面吹牛商蕴,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播芝发,決...
    沈念sama閱讀 41,220評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼绪商,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了辅鲸?” 一聲冷哼從身側(cè)響起格郁,我...
    開封第一講書人閱讀 40,167評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎独悴,沒想到半個月后理张,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,698評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡绵患,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,767評論 3 343
  • 正文 我和宋清朗相戀三年雾叭,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片落蝙。...
    茶點故事閱讀 40,912評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡织狐,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出筏勒,到底是詐尸還是另有隱情移迫,我是刑警寧澤,帶...
    沈念sama閱讀 36,572評論 5 351
  • 正文 年R本政府宣布管行,位于F島的核電站厨埋,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏捐顷。R本人自食惡果不足惜荡陷,卻給世界環(huán)境...
    茶點故事閱讀 42,254評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望迅涮。 院中可真熱鬧废赞,春花似錦、人聲如沸叮姑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,746評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至耘沼,卻和暖如春极颓,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背群嗤。 一陣腳步聲響...
    開封第一講書人閱讀 33,859評論 1 274
  • 我被黑心中介騙來泰國打工讼昆, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人骚烧。 一個月前我還...
    沈念sama閱讀 49,359評論 3 379
  • 正文 我出身青樓浸赫,卻偏偏與公主長得像,于是被迫代替她去往敵國和親赃绊。 傳聞我的和親對象是個殘疾皇子既峡,可洞房花燭夜當晚...
    茶點故事閱讀 45,922評論 2 361

推薦閱讀更多精彩內(nèi)容

  • 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的...
    西木閱讀 30,569評論 33 466
  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,734評論 0 9
  • 本文轉(zhuǎn)載自:http://southpeak.github.io/2014/10/25/objective-c-r...
    idiot_lin閱讀 937評論 0 4
  • Objective-C語言是一門動態(tài)語言碧查,他將很多靜態(tài)語言在編譯和鏈接時期做的事情放到了運行時來處理运敢。這種動態(tài)語言...
    tigger丨閱讀 1,408評論 0 8
  • 記得還在學校的時候,同寢室有一個女生開始看瑯琊榜忠售,她是看過小說再追劇的传惠,每天兩集,必追稻扬。期間不止有一個朋友向我強推...
    LunaCho_閱讀 496評論 0 0