一. Cell重?用
1. 數(shù)據(jù)源?方法優(yōu)化
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
在可?的??會重復(fù)繪制??,每次刷新顯示都會去創(chuàng)建新的Cell,非常耗費(fèi)性能。
解決?案:
?先創(chuàng)建?個靜態(tài)變量reuseID(代理方法返回Cell會調(diào)?用很多次,防?重復(fù)創(chuàng)建扯再,static保證只會被創(chuàng)建?次,提?性能)址遇,然后熄阻,從緩存池中取相應(yīng) identifier的Cell并更新數(shù)據(jù),如果沒有倔约,才開始alloc新的Cell秃殉,并用identifier標(biāo)識 Cell。每個Cell都會注冊?個identifier(重用標(biāo)識符)放?入緩存池,當(dāng)需要調(diào)?的時候就直接從緩存池里找對應(yīng)的id钾军,當(dāng)不需要時就放入緩存池等待調(diào)?鳄袍。(移出屏幕的 Cell才會放?入緩存池中,并不不會被release)所以在數(shù)據(jù)源?法中做出如下
優(yōu)化:
static NSString *reuseID = “reuseCellID”;
// 緩存池中取已經(jīng)創(chuàng)建的cell
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseID];
2. 緩存池的實(shí)現(xiàn)
當(dāng)Cell要alloc時吏恭,UITableView會在堆中開辟?一段內(nèi)存以供Cell緩存之?用拗小。Cell的重 ?用通過identifier標(biāo)識不同類型的Cell,由此可以推斷出樱哼,緩存池外層可能是?個可變字典哀九,通過key來取出內(nèi)部的Cell,?而緩存池為存儲不同高度搅幅、不同類型(包含圖片阅束、 Label等)的Cell,可以推斷出緩存池的字典內(nèi)部可能是一個可變數(shù)組茄唐,用來存放不不同 類型的Cell息裸,緩存池中只會保存已經(jīng)被移出屏幕的不同類型的Cell。
3. 緩存池獲取可重用Cell兩個?法的區(qū)別
-(nullable __kindof UITableViewCell *)dequeueReusableCellWithIdentifier: (NSString *)identifier;
這個?法會查詢可重?用Cell琢融,如果注冊了原型Cell界牡,能夠查詢到簿寂,否則漾抬,返回nil;?且需要判斷if(cell == nil),才會創(chuàng)建Cell常遂,不推薦
-(__kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(6_0);
使?這個?法之前纳令,必須通過xib(storyboard)或是Class(純代碼)注冊可重?用 Cell,?而且這個方法?定會返回一個Cell
//注冊Cell
- (void)registerNib:(nullable UINib *)nib forCellReuseIdentifier:(NSString
*)identifier NS_AVAILABLE_IOS(5_0);
- (void)registerClass:(nullable Class)cellClass forCellReuseIdentifier:(NSString *)identifier NS_AVAILABLE_IOS(6_0);
好處:
如果緩沖區(qū) Cell 不存在克胳,會使用原型 Cell 實(shí)例例化?個新的 Cell平绩,不需要再判 斷,同時代碼結(jié)構(gòu)更清晰漠另。
二. 定義?種(盡量少)類型的Cell及善?hidden隱藏(顯示)subviews
1. ?種類型的Cell
分析Cell結(jié)構(gòu)捏雌,盡可能的將 相同內(nèi)容的抽取到?種樣式Cell中,前?面已經(jīng)提到了了
Cell的重?機(jī)制笆搓,這樣就能保證UITbaleView要顯示多少內(nèi)容性湿,真正創(chuàng)建出的Cell可能 只比屏幕顯示的Cell多?點(diǎn)。雖然Cell的’體積’可能會大點(diǎn)满败,但是因?yàn)镃ell的數(shù)量量不會很多肤频,完全可以接受的。
好處:
- 減少代碼量量算墨,減少Nib?件的數(shù)量宵荒,統(tǒng)?一個Nib?文件定義Cell,容易修改、維護(hù)
- 基于Cell的重?用报咳,真正運(yùn)?時鋪滿屏幕所需的Cell數(shù)量?致是固定的侠讯,設(shè)為N個。所 以如果如果只有一種Cell暑刃,那就是只有N個Cell的實(shí)例;但是如果有M種Cell继低,那么運(yùn)行時最多可能會是“M x N = MN”個Cell的實(shí)例例,雖然可能并不會占?用太多內(nèi)存稍走,但是能少點(diǎn)不是更好嗎袁翁。
2. 善用hidden隱藏(顯示)subviews
只定義?種Cell,那該如何顯示不同類型的內(nèi)容呢?
答案就是婿脸,把所有不同類型的 view都定義好粱胜,放在cell??,通過hidden顯示狐树、隱藏焙压,來顯示不同類型的內(nèi)容。畢竟抑钟,在?戶快速滑動中涯曲,只是單純的顯示、隱藏subview比實(shí)時創(chuàng)建要快得多在塔。
三. 提前計(jì)算并緩存Cell的?高度
在iOS中幻件,不設(shè)UITableViewCell的預(yù)估行高的情況下,會優(yōu)先調(diào)用 ”tableView:heightForRowAtIndexPath:”?法蛔溃,獲取每個Cell的即將顯示的高度绰沥, 從而確定UITableView的布局,實(shí)際就是要獲取contentSize(UITableView繼承?UIScrollView,只有獲取滾動區(qū)域贺待,才能實(shí)現(xiàn)滾動),然后才調(diào)用”tableView:cellForRowAtIndexPath”,獲取每個Cell徽曲,進(jìn)?賦值。如果項(xiàng)?中模塊有 10000個Cell需要顯示麸塞,可想?知...
解決?案:
我個?認(rèn)為秃臣,可以創(chuàng)建?個frame模型,提前計(jì)算每個Cell的?高度哪工。參考其中一篇博客的時候奥此,在解決這個問題的時候,可以將計(jì)算Cell的?高度放?入數(shù)據(jù)模 型正勒,但這與MVC設(shè)計(jì)模式可能稍微有點(diǎn)沖突得院,這個時候我就想到MVVM這種設(shè)計(jì)模式,這個時候才能稍微有點(diǎn)MVVM這種設(shè)計(jì)模式的優(yōu)點(diǎn)(其實(shí)還是很不理理解的)章贞,可 以講計(jì)算Cell?高度放入ViewModel(視圖模型)中祥绞,讓Model(數(shù)據(jù)模型)只負(fù)責(zé)處理數(shù)據(jù)非洲。
四.異步繪制(自定義Cell繪制)
遇到?較復(fù)雜的界?面的時候,如復(fù)雜點(diǎn)的圖文混排蜕径,上?的那種優(yōu)化行高的?式可
能就不能滿?要求了两踏,當(dāng)然了,由于我的開發(fā)經(jīng)驗(yàn)尚短兜喻,說實(shí)話梦染,還沒遇到要將?定義的Cell重新繪制
五.滑動時,按需加載
開發(fā)的過程中自定義Cell的種類千奇百怪朴皆,但Cell本來就是?來顯示數(shù)據(jù)的帕识,不說100%帶有圖片,也差不多遂铡,這個時候就要考慮肮疗,下滑的過程中可能會有點(diǎn)卡頓,尤其網(wǎng)絡(luò)不好的時候扒接,異步加載圖片是個程序員都會想到伪货,但是如果給每個循環(huán)對象都加上異步加載,開啟的線程太多钾怔,?樣會卡頓碱呼,我記得好像線程條數(shù)?般3-5條,最多也就6條吧宗侦。這個時候利利?用UIScrollViewDelegate兩個代理方法就能很好地解決這個問題愚臀。
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate: (BOOL)decelerate
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
六.緩存View
當(dāng)Cell中的部分View是?常獨(dú)立的,并且不便于重?的凝垛,而且“體積”?常小懊悯,在內(nèi)存可控的前提下,我們完全可以將這些view緩存起來梦皮。當(dāng)然也是緩存在模型中。
七.避免?量的圖片縮放桃焕、顏?漸變等剑肯,盡量顯示“大?剛好合適的圖片資源”
八.避免同步的從網(wǎng)絡(luò)、文件獲取數(shù)據(jù)观堂,Cell內(nèi)實(shí)現(xiàn)的內(nèi)容來自web让网,使用異步加載,緩存請求結(jié)果
九.渲染
1. 減少subviews的個數(shù)和層級
?子控件的層級越深师痕,渲染到屏幕上所需要的計(jì)算量量就越大;如多用drawRect繪制元素溃睹,替代?view顯示
2. 少?用subviews的透明圖層
對于不透明的View,設(shè)置opaque為YES胰坟,這樣在繪制該View時因篇,就不需要考慮被View覆蓋的其他內(nèi)容(盡量設(shè)置Cell的view為opaque,避免GPU對Cell下?的內(nèi)容 也進(jìn)行繪制)
3. 避免CALayer特效(shadowPath) 給Cell中View加陰影會引起性能問題,如下面代碼會導(dǎo)致滾動時有明顯的卡頓:
view.layer.shadowColor = color.CGColor;
view.layer.shadowOffset = offset;
view.layer.shadowOpacity = 1;
view.layer.shadowRadius = radius;