ios 經(jīng)典面試案例 (五)

1.OS app啟動(dòng)如何優(yōu)化?

1. 我們可以通過(guò)在 Xcode 中 Edit scheme -> Run -> Auguments 將環(huán)境變量 DYLD_PRINT_STATISTICS 設(shè)為 1,在控制臺(tái)看到main()函數(shù)之前的啟動(dòng)時(shí)間。

2. 分解優(yōu)化目標(biāo) 分步達(dá)到優(yōu)化目的

   1). 耗時(shí)操作異步處理

   2). 如果啟動(dòng)流程依賴網(wǎng)絡(luò)請(qǐng)求回來(lái)才能繼續(xù),那么需要考慮網(wǎng)絡(luò)極差情況下的啟動(dòng)速度

   3). 如果APP有l(wèi)oading廣告頁(yè)并且對(duì)分辨率的要求較高,請(qǐng)嘗試做緩存吧

   4). 主頁(yè)面Controller中的viewDidLoad和viewWillAppear方法中盡量少做事情

   5). 排查清理項(xiàng)目中未使用到的類庫(kù)以及Framework

   6). 刪減合并一些OC類,刪減沒(méi)有用到或者可以不用的靜態(tài)變量、方法等

   7). 輕量化+load方法中的內(nèi)容,可延遲到+initialize中

2.copy與mutableCopy的理解?

使用copy或mutableCopy方法可以創(chuàng)建一個(gè)對(duì)象的副本

copy

需要實(shí)現(xiàn)NSCoppying協(xié)議

這些創(chuàng)建的是不可變副本(如NSString、NSArray、NSDictionary)

Copy的目的是建立副本,同時(shí)修改原始對(duì)象和復(fù)本不會(huì)互相干擾

mutableCopy

需要先實(shí)現(xiàn)NSMutableCopying協(xié)議

創(chuàng)建的是可變副本(如NSMutableString、NSMutableArray、NSMutableDictionary)

3.UITableView性能優(yōu)化

1)Cell重用

  • 1.1>數(shù)據(jù)源方法優(yōu)化
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;

在可見(jiàn)的頁(yè)面會(huì)重復(fù)繪制頁(yè)面,每次刷新顯示都會(huì)去創(chuàng)建新的Cell,非常耗費(fèi)性能。
** 解決方案:**首先創(chuàng)建一個(gè)靜態(tài)變量reuseID(代理方法返回Cell會(huì)調(diào)用很多次,防止重復(fù)創(chuàng)建,static保證只會(huì)被創(chuàng)建一次,提高性能),然后,從緩存池中取相應(yīng)identifier的Cell并更新數(shù)據(jù),如果沒(méi)有,才開始alloc新的Cell,并用identifier標(biāo)識(shí)Cell。每個(gè)Cell都會(huì)注冊(cè)一個(gè)identifier(重用標(biāo)識(shí)符)放入緩存池,當(dāng)需要調(diào)用的時(shí)候就直接從緩存池里找對(duì)應(yīng)的id,當(dāng)不需要時(shí)就放入緩存池等待調(diào)用。(移出屏幕的Cell才會(huì)放入緩存池中,并不會(huì)被release)所以在數(shù)據(jù)源方法中做出如下優(yōu)化:
// 調(diào)用次數(shù)太多,static 保證只創(chuàng)建一次reuseID,提高性能
static NSString *reuseID = “reuseCellID”;
// 緩存池中取已經(jīng)創(chuàng)建的cell

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseID];
  • 1.2>緩存池的實(shí)現(xiàn)
    當(dāng)Cell要alloc時(shí),UITableView會(huì)在堆中開辟一段內(nèi)存以供Cell緩存之用。Cell的重用通過(guò)identifier標(biāo)識(shí)不同類型的Cell,由此可以推斷出,緩存池外層可能是一個(gè)可變字典,通過(guò)key來(lái)取出內(nèi)部的Cell,而緩存池為存儲(chǔ)不同高度、不同類型(包含圖片、Label等)的Cell,可以推斷出緩存池的字典內(nèi)部可能是一個(gè)可變數(shù)組,用來(lái)存放不同類型的Cell,緩存池中只會(huì)保存已經(jīng)被移出屏幕的不同類型的Cell。
  • 1.3>緩存池獲取可重用Cell兩個(gè)方法的區(qū)別
-(nullable __kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier; 
這個(gè)方法會(huì)查詢可重用Cell,如果注冊(cè)了原型Cell,能夠查詢到,否則,返回nil;而且需要判斷if(cell == nil),才會(huì)創(chuàng)建Cell,不推薦
-(__kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(6_0);
 使用這個(gè)方法之前,必須通過(guò)xib(storyboard)或是Class(純代碼)注冊(cè)可重用Cell,而且這個(gè)方法一定會(huì)返回一個(gè)Cell

注冊(cè)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 不存在,會(huì)使用原型 Cell 實(shí)例化一個(gè)新的 Cell,不需要再判斷,同時(shí)代碼結(jié)構(gòu)更清晰。

2)定義一種(盡量少)類型的Cell及善用hidden隱藏(顯示)subviews

  • 2.1>一種類型的Cell
    分析Cell結(jié)構(gòu),盡可能的將 相同內(nèi)容的抽取到一種樣式Cell中,前面已經(jīng)提到了Cell的重用機(jī)制,這樣就能保證UITbaleView要顯示多少內(nèi)容,真正創(chuàng)建出的Cell可能只比屏幕顯示的Cell多一點(diǎn)。雖然Cell的’體積’可能會(huì)大點(diǎn),但是因?yàn)镃ell的數(shù)量不會(huì)很多,完全可以接受的。好處:

    • 減少代碼量,減少Nib文件的數(shù)量,統(tǒng)一一個(gè)Nib文件定義Cell,容易修改、維護(hù)
    • 基于Cell的重用,真正運(yùn)行時(shí)鋪滿屏幕所需的Cell數(shù)量大致是固定的,設(shè)為N個(gè)。所以如果如果只有一種Cell,那就是只有N個(gè)Cell的實(shí)例;但是如果有M種Cell,那么運(yùn)行時(shí)最多可能會(huì)是“M x N = MN”個(gè)Cell的實(shí)例,雖然可能并不會(huì)占用太多內(nèi)存,但是能少點(diǎn)不是更好嗎。
  • 2.2>善用hidden隱藏(顯示)subviews
    只定義一種Cell,那該如何顯示不同類型的內(nèi)容呢?答案就是,把所有不同類型的view都定義好,放在cell里面,通過(guò)hidden顯示、隱藏,來(lái)顯示不同類型的內(nèi)容。畢竟,在用戶快速滑動(dòng)中,只是單純的顯示、隱藏subview比實(shí)時(shí)創(chuàng)建要快得多。

3)提前計(jì)算并緩存Cell的高度
在iOS中,不設(shè)UITableViewCell的預(yù)估行高的情況下,會(huì)優(yōu)先調(diào)用”tableView:heightForRowAtIndexPath:”方法,獲取每個(gè)Cell的即將顯示的高度,從而確定UITableView的布局,實(shí)際就是要獲取contentSize(UITableView繼承自UIScrollView,只有獲取滾動(dòng)區(qū)域,才能實(shí)現(xiàn)滾動(dòng)),然后才調(diào)用”tableView:cellForRowAtIndexPath”,獲取每個(gè)Cell,進(jìn)行賦值。如果項(xiàng)目中模塊有10000個(gè)Cell需要顯示,可想而知…

解決方案:我個(gè)人認(rèn)為,可以創(chuàng)建一個(gè)frame模型,提前計(jì)算每個(gè)Cell的高度。參考其中一篇博客的時(shí)候,在解決這個(gè)問(wèn)題的時(shí)候,可以將計(jì)算Cell的高度放入數(shù)據(jù)模型,但這與MVC設(shè)計(jì)模式可能稍微有點(diǎn)沖突,這個(gè)時(shí)候我就想到MVVM這種設(shè)計(jì)模式,這個(gè)時(shí)候才能稍微有點(diǎn)MVVM這種設(shè)計(jì)模式的優(yōu)點(diǎn)(其實(shí)還是很不理解的),可以講計(jì)算Cell高度放入ViewModel(視圖模型)中,讓Model(數(shù)據(jù)模型)只負(fù)責(zé)處理數(shù)據(jù)。

4)異步繪制(自定義Cell繪制)
遇到比較復(fù)雜的界面的時(shí)候,如復(fù)雜點(diǎn)的圖文混排,上面的那種優(yōu)化行高的方式可能就不能滿足要求了,當(dāng)然了,由于我的開發(fā)經(jīng)驗(yàn)尚短,說(shuō)實(shí)話,還沒(méi)遇到要將自定義的Cell重新繪制

5)滑動(dòng)時(shí),按需加載
開發(fā)的過(guò)程中,自定義Cell的種類千奇百怪,但Cell本來(lái)就是用來(lái)顯示數(shù)據(jù)的,不說(shuō)100%帶有圖片,也差不多,這個(gè)時(shí)候就要考慮,下滑的過(guò)程中可能會(huì)有點(diǎn)卡頓,尤其網(wǎng)絡(luò)不好的時(shí)候,異步加載圖片是個(gè)程序員都會(huì)想到,但是如果給每個(gè)循環(huán)對(duì)象都加上異步加載,開啟的線程太多,一樣會(huì)卡頓,我記得好像線程條數(shù)一般3-5條,最多也就6條吧。這個(gè)時(shí)候利用UIScrollViewDelegate兩個(gè)代理方法就能很好地解決這個(gè)問(wèn)題。

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView

6)緩存View
當(dāng)Cell中的部分View是非常獨(dú)立的,并且不便于重用的,而且“體積”非常小,在內(nèi)存可控的前提下,我們完全可以將這些view緩存起來(lái)。當(dāng)然也是緩存在模型中。

7)避免大量的圖片縮放、顏色漸變等,盡量顯示“大小剛好合適的圖片資源”

8)避免同步的從網(wǎng)絡(luò)、文件獲取數(shù)據(jù),Cell內(nèi)實(shí)現(xiàn)的內(nèi)容來(lái)自web,使用異步加載,緩存請(qǐng)求結(jié)果

9)渲染

  • 9.1>減少subviews的個(gè)數(shù)和層級(jí)
    子控件的層級(jí)越深,渲染到屏幕上所需要的計(jì)算量就越大;如多用drawRect繪制元素,替代用view顯示
  • 9.2>少用subviews的透明圖層
    對(duì)于不透明的View,設(shè)置opaque為YES,這樣在繪制該View時(shí),就不需要考慮被View覆蓋的其他內(nèi)容(盡量設(shè)置Cell的view為opaque,避免GPU對(duì)Cell下面的內(nèi)容也進(jìn)行繪制)
  • 9.3>避免CALayer特效(shadowPath)
    給Cell中View加陰影會(huì)引起性能問(wèn)題,如下面代碼會(huì)導(dǎo)致滾動(dòng)時(shí)有明顯的卡頓:
view.layer.shadowColor = color.CGColor;
view.layer.shadowOffset = offset;
view.layer.shadowOpacity = 1;
view.layer.shadowRadius = radius;

題的搬運(yùn),不成敬意!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 看到這幅畫的時(shí)候,我就在想,是一個(gè)什么樣的女性畫出了這樣的一幅圖案,這個(gè)畫作給我的感覺(jué)是安靜,安靜中透出一些孤獨(dú)。...
    周米啊閱讀 455評(píng)論 2 2
  • 爸爸看手機(jī)和抽煙和喝酒。在寫就寫媽媽的啊?干活兒干活兒干活兒愛(ài)花那會(huì)兒這是媽媽讓除了干活就是干活,干活。干活兒干活兒……
    大琪_b0d6閱讀 363評(píng)論 0 0
  • “太美了!”就在邁進(jìn)教室的瞬間,我的目光被孩子們制作的精美手抄報(bào)所吸引:有的色彩斑斕如夏日般絢爛、有的淡雅如...
    唯美兒閱讀 338評(píng)論 8 5
  • 計(jì)劃6件事,都一一完成了,或許還不夠完美。 白天工作總是很犯困,因?yàn)檎{(diào)了新位置,太陽(yáng)直曬的關(guān)系嗎?(午休不能少哪...
    Ada彩英閱讀 179評(píng)論 0 0

友情鏈接更多精彩內(nèi)容