一. Cell重?用
1. 數(shù)據(jù)源?方法優(yōu)化
- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath;
在可?的??會重復(fù)繪制??,每次刷新顯示都會去創(chuàng)建新的Cell,非常耗費性能。
解決?案:
?先創(chuàng)建?個靜態(tài)變量reuseID(代理方法返回Cell會調(diào)?用很多次,防?重復(fù)創(chuàng)建,static保證只會被創(chuàng)建?次,提?性能),然后,從緩存池中取相應(yīng) identifier的Cell并更新數(shù)據(jù),如果沒有,才開始alloc新的Cell,并用identifier標識 Cell。每個Cell都會注冊?個identifier(重用標識符)放?入緩存池,當需要調(diào)?的時候就直接從緩存池里找對應(yīng)的id,當不需要時就放入緩存池等待調(diào)?。(移出屏幕的 Cell才會放?入緩存池中,并不不會被release)所以在數(shù)據(jù)源?法中做出如下
優(yōu)化:
staticNSString*reuseID = “reuseCellID”;// 緩存池中取已經(jīng)創(chuàng)建的cellUITableViewCell*cell = [tableView dequeueReusableCellWithIdentifier:reuseID];
2. 緩存池的實現(xiàn)
當Cell要alloc時,UITableView會在堆中開辟?一段內(nèi)存以供Cell緩存之?用。Cell的重 ?用通過identifier標識不同類型的Cell,由此可以推斷出,緩存池外層可能是?個可變字典,通過key來取出內(nèi)部的Cell,?而緩存池為存儲不同高度、不同類型(包含圖片、 Label等)的Cell,可以推斷出緩存池的字典內(nèi)部可能是一個可變數(shù)組,用來存放不不同 類型的Cell,緩存池中只會保存已經(jīng)被移出屏幕的不同類型的Cell。
3. 緩存池獲取可重用Cell兩個?法的區(qū)別
-(nullable__kindofUITableViewCell*)dequeueReusableCellWithIdentifier: (NSString*)identifier;這個?法會查詢可重?用Cell,如果注冊了原型Cell,能夠查詢到,否則,返回nil;?且需要判斷if(cell ==nil),才會創(chuàng)建Cell,不推薦-(__kindofUITableViewCell*)dequeueReusableCellWithIdentifier:(NSString*)identifier forIndexPath:(NSIndexPath*)indexPathNS_AVAILABLE_IOS(6_0);使?這個?法之前,必須通過xib(storyboard)或是Class(純代碼)注冊可重?用 Cell,?而且這個方法?定會返回一個Cell//注冊Cell- (void)registerNib:(nullableUINib*)nib forCellReuseIdentifier:(NSString*)identifierNS_AVAILABLE_IOS(5_0);- (void)registerClass:(nullableClass)cellClass forCellReuseIdentifier:(NSString*)identifierNS_AVAILABLE_IOS(6_0);
好處:
如果緩沖區(qū) Cell 不存在,會使用原型 Cell 實例例化?個新的 Cell,不需要再判 斷,同時代碼結(jié)構(gòu)更清晰。
二. 定義?種(盡量少)類型的Cell及善?hidden隱藏(顯示)subviews
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ù)量?致是固定的,設(shè)為N個。所 以如果如果只有一種Cell,那就是只有N個Cell的實例;但是如果有M種Cell,那么運行時最多可能會是“M x N = MN”個Cell的實例例,雖然可能并不會占?用太多內(nèi)存,但是能少點不是更好嗎。
2. 善用hidden隱藏(顯示)subviews
只定義?種Cell,那該如何顯示不同類型的內(nèi)容呢?
答案就是,把所有不同類型的 view都定義好,放在cell??,通過hidden顯示、隱藏,來顯示不同類型的內(nèi)容。畢竟,在?戶快速滑動中,只是單純的顯示、隱藏subview比實時創(chuàng)建要快得多。
三. 提前計算并緩存Cell的?高度
在iOS中,不設(shè)UITableViewCell的預(yù)估行高的情況下,會優(yōu)先調(diào)用 ”tableView:heightForRowAtIndexPath:”?法,獲取每個Cell的即將顯示的高度, 從而確定UITableView的布局,實際就是要獲取contentSize(UITableView繼承?UIScrollView,只有獲取滾動區(qū)域,才能實現(xiàn)滾動),然后才調(diào)用”tableView:cellForRowAtIndexPath”,獲取每個Cell,進?賦值。如果項?中模塊有 10000個Cell需要顯示,可想?知...
解決?案:
我個?認為,可以創(chuàng)建?個frame模型,提前計算每個Cell的?高度。參考其中一篇博客的時候,在解決這個問題的時候,可以將計算Cell的?高度放?入數(shù)據(jù)模 型,但這與MVC設(shè)計模式可能稍微有點沖突,這個時候我就想到MVVM這種設(shè)計模式,這個時候才能稍微有點MVVM這種設(shè)計模式的優(yōu)點(其實還是很不理理解的),可 以講計算Cell?高度放入ViewModel(視圖模型)中,讓Model(數(shù)據(jù)模型)只負責處理數(shù)據(jù)。
四.異步繪制(自定義Cell繪制)
遇到?較復(fù)雜的界?面的時候,如復(fù)雜點的圖文混排,上?的那種優(yōu)化行高的?式可
能就不能滿?要求了,當然了,由于我的開發(fā)經(jīng)驗尚短,說實話,還沒遇到要將?定義的Cell重新繪制
五.滑動時,按需加載
開發(fā)的過程中自定義Cell的種類千奇百怪,但Cell本來就是?來顯示數(shù)據(jù)的,不說100%帶有圖片,也差不多,這個時候就要考慮,下滑的過程中可能會有點卡頓,尤其網(wǎng)絡(luò)不好的時候,異步加載圖片是個程序員都會想到,但是如果給每個循環(huán)對象都加上異步加載,開啟的線程太多,?樣會卡頓,我記得好像線程條數(shù)?般3-5條,最多也就6條吧。這個時候利利?用UIScrollViewDelegate兩個代理方法就能很好地解決這個問題。
- (void)scrollViewDidEndDragging:(UIScrollView*)scrollView willDecelerate: (BOOL)decelerate- (void)scrollViewDidEndDecelerating:(UIScrollView*)scrollView
六.緩存View
當Cell中的部分View是?常獨立的,并且不便于重?的,而且“體積”?常小,在內(nèi)存可控的前提下,我們完全可以將這些view緩存起來。當然也是緩存在模型中。
七.避免?量的圖片縮放、顏?漸變等,盡量顯示“大?剛好合適的圖片資源”
八.避免同步的從網(wǎng)絡(luò)、文件獲取數(shù)據(jù),Cell內(nèi)實現(xiàn)的內(nèi)容來自web,使用異步加載,緩存請求結(jié)果
九.渲染
1. 減少subviews的個數(shù)和層級
?子控件的層級越深,渲染到屏幕上所需要的計算量量就越大;如多用drawRect繪制元素,替代?view顯示
2. 少?用subviews的透明圖層
對于不透明的View,設(shè)置opaque為YES,這樣在繪制該View時,就不需要考慮被View覆蓋的其他內(nèi)容(盡量設(shè)置Cell的view為opaque,避免GPU對Cell下?的內(nèi)容 也進行繪制)
3. 避免CALayer特效(shadowPath) 給Cell中View加陰影會引起性能問題,如下面代碼會導致滾動時有明顯的卡頓:
view.layer.shadowColor = color.CGColor;
view.layer.shadowOffset = offset;
view.layer.shadowOpacity = 1;
view.layer.shadowRadius = radius;