iOS面試題:簡述性能優(yōu)化

在性能優(yōu)化中一個最具參考價值的屬性是FPS:Frames Per Second,其實就是屏幕刷新率馏慨,蘋果的iphone推薦的刷新率是60Hz爹橱,也就是說GPU每秒鐘刷新屏幕60次,這每刷新一次就是一幀frame煞额,F(xiàn)PS也就是每秒鐘刷新多少幀畫面袭景。靜止不變的頁面FPS值是0挡育,這個值是沒有參考意義的绒瘦,只有當頁面在執(zhí)行動畫或者滑動的時候称簿,F(xiàn)PS值才具有參考價值,F(xiàn)PS值的大小體現(xiàn)了頁面的流暢程度高低惰帽,當?shù)陀?5的時候卡頓會比較明顯憨降。

圖層混合:

每一個layer是一個紋理,所有的紋理都以某種方式堆疊在彼此的頂部该酗。對于屏幕上的每一個像素授药,GPU需要算出怎么混合這些紋理來得到像素RGB的值。

當Sa = 0.5時呜魄,RGB值為(0.5, 0, 0)悔叽,可以看出,當兩個不是完全不透明的CALayer覆蓋在一起時,GPU大量做這種復(fù)合操作爵嗅,隨著這中操作的越多骄蝇,GPU越忙碌,性能肯定會受到影響操骡。

公式:

R = S + D * ( 1 – Sa )

結(jié)果的顏色是源色彩(頂端紋理)+目標顏色(低一層的紋理)*(1-源顏色的透明度)。

當Sa = 1時赚窃,R = S,GPU將不會做任何合成册招,而是簡單從這個層拷貝,不需要考慮它下方的任何東西(因為都被它遮擋住了)勒极,這節(jié)省了GPU相當大的工作量是掰。

一、入門級

1辱匿、用ARC管理內(nèi)存
2键痛、在正確的地方使用 reuseIdentifier
3炫彩、盡量把views設(shè)置為透明
4、避免過于龐大的XIB
5絮短、不要阻塞主線程

6江兢、在ImageViews中調(diào)整圖片大小。如果要在UIImageView中顯示一個來自bundle的圖片丁频,你應(yīng)保證圖片的大小和UIImageView的大小相同杉允。在運行中縮放圖片是很耗費資源的,特別是UIImageView嵌套在UIScrollView中的情況下席里。如果圖片是從遠端服務(wù)加載的你不能控制圖片大小叔磷,比如在下載前調(diào)整到合適大小的話,你可以在下載完成后奖磁,最好是用background
thread改基,縮放一次,然后在UIImageView中使用縮放后的圖片咖为。

7秕狰、選擇正確的Collection。

  • Arrays: 有序的一組值案疲。使用index來lookup很快封恰,使用value lookup很慢, 插入/刪除很慢褐啡。
  • Dictionaries: 存儲鍵值對诺舔。 用鍵來查找比較快。
  • Sets: 無序的一組值备畦。用值來查找很快低飒,插入/刪除很快。

8懂盐、打開gzip壓縮褥赊。app可能大量依賴于服務(wù)器資源,問題是我們的目標是移動設(shè)備莉恼,因此你就不能指望網(wǎng)絡(luò)狀況有多好拌喉。減小文檔的一個方式就是在服務(wù)端和你的app中打開gzip。這對于文字這種能有更高壓縮率的數(shù)據(jù)來說會有更顯著的效用俐银。
iOS已經(jīng)在NSURLConnection中默認支持了gzip壓縮尿背,當然AFNetworking這些基于它的框架亦然。

二捶惜、中級

1田藐、重用和延遲加載(lazy load) Views

  • 更多的view意味著更多的渲染,也就是更多的CPU和內(nèi)存消耗,對于那種嵌套了很多view在UIScrollView里邊的app更是如此汽久。

  • 這里我們用到的技巧就是模仿UITableView和UICollectionView的操作: 不要一次創(chuàng)建所有的subview鹤竭,而是當需要時才創(chuàng)建,當它們完成了使命景醇,把他們放進一個可重用的隊列中臀稚。這樣的話你就只需要在滾動發(fā)生時創(chuàng)建你的views,避免了不劃算的內(nèi)存分配啡直。
    2烁涌、Cache, Cache, 還是Cache!

  • 一個極好的原則就是,緩存所需要的酒觅,也就是那些不大可能改變但是需要經(jīng)常讀取的東西撮执。

  • 我們能緩存些什么呢?一些選項是舷丹,遠端服務(wù)器的響應(yīng)抒钱,圖片,甚至計算結(jié)果颜凯,比如UITableView的行高谋币。

  • NSCache和NSDictionary類似,不同的是系統(tǒng)回收內(nèi)存的時候它會自動刪掉它的內(nèi)容症概。
    3蕾额、權(quán)衡渲染方法.性能能還是要bundle保持合適的大小。

4彼城、處理內(nèi)存警告.移除對緩存诅蝶,圖片object和其他一些可以重創(chuàng)建的objects的strong references.

5、重用大開銷對象

6募壕、一些objects的初始化很慢调炬,比如NSDateFormatter和NSCalendar。然而舱馅,你又不可避免地需要使用它們缰泡,比如從JSON或者XML中解析數(shù)據(jù)。想要避免使用這個對象的瓶頸你就需要重用他們代嗤,可以通過添加屬性到你的class里或者創(chuàng)建靜態(tài)變量來實現(xiàn)棘钞。

7、避免反復(fù)處理數(shù)據(jù).在服務(wù)器端和客戶端使用相同的數(shù)據(jù)結(jié)構(gòu)很重要干毅。

8宜猜、選擇正確的數(shù)據(jù)格式.解析JSON會比XML更快一些,JSON也通常更小更便于傳輸溶锭。從iOS5起有了官方內(nèi)建的JSON deserialization 就更加方便使用了。但是XML也有XML的好處符隙,比如使用SAX 來解析XML就像解析本地文件一樣趴捅,你不需像解析json一樣等到整個文檔下載完成才開始解析垫毙。當你處理很大的數(shù)據(jù)的時候就會極大地減低內(nèi)存消耗和增加性能。

9拱绑、正確設(shè)定背景圖片

  • 全屏背景圖综芥,在view中添加一個UIImageView作為一個子View
  • 只是某個小的view的背景圖,你就需要用UIColor的colorWithPatternImage來做了猎拨,它會更快地渲染也不會花費很多內(nèi)存:
    10膀藐、減少使用Web特性。想要更高的性能你就要調(diào)整下你的HTML了红省。第一件要做的事就是盡可能移除不必要的javascript,避免使用過大的框架。能只用原生js就更好了猾普。盡可能異步加載例如用戶行為統(tǒng)計script這種不影響頁面表達的javascript翠霍。注意你使用的圖片,保證圖片的符合你使用的大小痕寓。

11傲醉、Shadow Path 。CoreAnimation不得不先在后臺得出你的圖形并加好陰影然后才渲染呻率,這開銷是很大的硬毕。使用shadowPath的話就避免了這個問題。使用shadow path的話iOS就不必每次都計算如何渲染礼仗,它使用一個預(yù)先計算好的路徑吐咳。但問題是自己計算path的話可能在某些View中比較困難,且每當view的frame變化的時候你都需要去update shadow path.

12藐守、優(yōu)化Table View

  • 正確使用reuseIdentifier來重用cells

  • 盡量使所有的view opaque挪丢,包括cell自身

  • 避免漸變,圖片縮放卢厂,后臺選人

  • 緩存行高

  • 如果cell內(nèi)現(xiàn)實的內(nèi)容來自web乾蓬,使用異步加載,緩存請求結(jié)果

  • 使用shadowPath來畫陰影

  • 減少subviews的數(shù)量

  • 盡量不適用cellForRowAtIndexPath:慎恒,如果你需要用到它任内,只用-一次然后緩存結(jié)果

  • 使用正確的數(shù)據(jù)結(jié)構(gòu)來存儲數(shù)據(jù)
    使用rowHeight, sectionFooterHeight 和 sectionHeaderHeight來設(shè)定固定的高,不要請求delegate
    13融柬、選擇正確的數(shù)據(jù)存儲選項

  • NSUserDefaults的問題是什么死嗦?雖然它很nice也很便捷,但是它只適用于小數(shù)據(jù)粒氧,比如一些簡單的布爾型的設(shè)置選項越除,再大點你就要考慮其它方式了

  • XML這種結(jié)構(gòu)化檔案呢?總體來說,你需要讀取整個文件到內(nèi)存里去解析摘盆,這樣是很不經(jīng)濟的翼雀。使用SAX又是一個很麻煩的事情。

  • NSCoding孩擂?不幸的是狼渊,它也需要讀寫文件,所以也有以上問題类垦。

  • 在這種應(yīng)用場景下狈邑,使用SQLite 或者 Core Data比較好。使用這些技術(shù)你用特定的查詢語句就能只加載你需要的對象蚤认。

  • 在性能層面來講米苹,SQLite和Core Data是很相似的。他們的不同在于具體使用方法烙懦。

  • Core Data代表一個對象的graph model驱入,但SQLite就是一個DBMS。

  • Apple在一般情況下建議使用Core Data氯析,但是如果你有理由不使用它亏较,那么就去使用更加底層的SQLite吧。

  • 如果你使用SQLite掩缓,你可以用FMDB這個庫來簡化SQLite的操作雪情,這樣你就不用花很多經(jīng)歷了解SQLite的C API了。

三你辣、高級

1巡通、加速啟動時間∩岷澹快速打開app是很重要的宴凉,特別是用戶第一次打開它時,對app來講表悬,第一印象太太太重要了弥锄。你能做的就是使它盡可能做更多的異步任務(wù),比如加載遠端或者數(shù)據(jù)庫數(shù)據(jù)蟆沫,解析數(shù)據(jù)籽暇。避免過于龐大的XIB,因為他們是在主線程上加載的饭庞。所以盡量使用沒有這個問題的Storyboards吧戒悠!一定要把設(shè)備從Xcode斷開來測試啟動速度

2、使用Autorelease Pool舟山。NSAutoreleasePool`負責釋放block中的autoreleased objects绸狐。一般情況下它會自動被UIKit調(diào)用卤恳。但是有些狀況下你也需要手動去創(chuàng)建它。假如你創(chuàng)建很多臨時對象寒矿,你會發(fā)現(xiàn)內(nèi)存一直在減少直到這些對象被release的時候纬黎。這是因為只有當UIKit用光了autorelease pool的時候memory才會被釋放。消息是你可以在你自己的@autoreleasepool里創(chuàng)建臨時的對象來避免這個行為劫窒。

3、選擇是否緩存圖片拆座。常見的從bundle中加載圖片的方式有兩種主巍,一個是用imageNamed,二是用imageWithContentsOfFile挪凑,第一種比較常見一點孕索。

4、避免日期格式轉(zhuǎn)換躏碳。如果你要用NSDateFormatter來處理很多日期格式搞旭,應(yīng)該小心以待。就像先前提到的菇绵,任何時候重用NSDateFormatters都是一個好的實踐肄渗。如果你可以控制你所處理的日期格式,盡量選擇Unix時間戳咬最。你可以方便地從時間戳轉(zhuǎn)換到NSDate:

- (NSDate*)dateFromUnixTimestamp:(NSTimeInterval)timestamp {
return[NSDate dateWithTimeIntervalSince1970:timestamp];
}

這樣會比用C來解析日期字符串還快翎嫡!需要注意的是,許多web API會以微秒的形式返回時間戳永乌,因為這種格式在javascript中更方便使用惑申。記住用dateFromUnixTimestamp之前除以1000就好了。

平時你是如何對代碼進行性能優(yōu)化的翅雏?

  • 利用性能分析工具檢測圈驼,包括靜態(tài) Analyze 工具,以及運行時 Profile 工具望几,通過Xcode工具欄中Product->Profile可以啟動,

  • 比如測試程序啟動運行時間绩脆,當點擊Time Profiler應(yīng)用程序開始運行后.就能獲取到整個應(yīng)用程序運行消耗時間分布和百分比.為了保證數(shù)據(jù)分析在統(tǒng)一使用場景真實需要注意一定要使用真機,因為此時模擬器是運行在Mac上,而Mac上的CPU往往比iOS設(shè)備要快橄妆。

  • 為了防止一個應(yīng)用占用過多的系統(tǒng)資源衙伶,開發(fā)iOS的蘋果工程師門設(shè)計了一個“看門狗”的機制。在不同的場景下害碾,“看門狗”會監(jiān)測應(yīng)用的性能矢劲。如果超出了該場景所規(guī)定的運行時間,“看門狗”就會強制終結(jié)這個應(yīng)用的進程慌随。開發(fā)者們在crashlog里面芬沉,會看到諸如0x8badf00d這樣的錯誤代碼躺同。

優(yōu)化Table View

  • 正確使用reuseIdentifier來重用cells
  • 盡量使所有的view opaque,包括cell自身
  • 如果cell內(nèi)現(xiàn)實的內(nèi)容來自web丸逸,使用異步加載蹋艺,緩存請求結(jié)果
    減少subviews的數(shù)量
  • 盡量不適用cellForRowAtIndexPath:,如果你需要用到它黄刚,只用一次然后緩存結(jié)果
  • 使用rowHeight, sectionFooterHeight和sectionHeaderHeight來設(shè)定固定的高捎谨,不要請求delegate

UIImage加載圖片性能問題

  • imagedNamed初始化

  • imageWithContentsOfFile初始化

  • imageNamed默認加載圖片成功后會內(nèi)存中緩存圖片,這個方法用一個指定的名字在系統(tǒng)緩存中查找并返回一個圖片對象.如果緩存中沒有找到相應(yīng)的圖片對象,則從指定地方加載圖片然后緩存對象,并返回這個圖片對象.

  • imageWithContentsOfFile則僅只加載圖片,不緩存.

  • 加載一張大圖并且使用一次憔维,用imageWithContentsOfFile是最好,這樣CPU不需要做緩存節(jié)約時間.

  • 使用場景需要編程時涛救,應(yīng)該根據(jù)實際應(yīng)用場景加以區(qū)分,UIimage雖小业扒,但使用元素較多問題會有所凸顯.

  • 不要在viewWillAppear 中做費時的操作:viewWillAppear: 在view顯示之前被調(diào)用检吆,出于效率考慮,方法中不要處理復(fù)雜費時操作程储;在該方法設(shè)置 view 的顯示屬性之類的簡單事情蹭沛,比如背景色,字體等章鲤。否則摊灭,會明顯感覺到 view 有卡頓或者延遲。

  • 在正確的地方使用reuseIdentifier:table view用 tableView:cellForRowAtIndexPath:為rows分配cells的時候败徊,它的數(shù)據(jù)應(yīng)該重用自UITableViewCell斟或。

  • 盡量把views設(shè)置為透明:如果你有透明的Views你應(yīng)該設(shè)置它們的opaque屬性為YES。系統(tǒng)用一個最優(yōu)的方式渲染這些views集嵌。這個簡單的屬性在IB或者代碼里都可以設(shè)定萝挤。

  • 避免過于龐大的XIB:盡量簡單的為每個Controller配置一個單獨的XIB,盡可能把一個View Controller的view層次結(jié)構(gòu)分散到單獨的XIB中去, 當你加載一個引用了圖片或者聲音資源的nib時根欧,nib加載代碼會把圖片和聲音文件寫進內(nèi)存怜珍。

  • 不要阻塞主線程:永遠不要使主線程承擔過多。因為UIKit在主線程上做所有工作凤粗,渲染酥泛,管理觸摸反應(yīng),回應(yīng)輸入等都需要在它上面完成,大部分阻礙主進程的情形是你的app在做一些牽涉到讀寫外部資源的I/O操作嫌拣,比如存儲或者網(wǎng)絡(luò)柔袁。
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // 選擇一個子線程來執(zhí)行耗時操作
    dispatch_async(dispatch_get_main_queue(), ^{
    // 返回主線程更新UI
    });
    });

  • 在Image Views中調(diào)整圖片大小
    如果要在UIImageView中顯示一個來自bundle的圖片,你應(yīng)保證圖片的大小和UIImageView的大小相同异逐。在運行中縮放圖片是很耗費資源的.

講講你用Instrument優(yōu)化動畫性能的經(jīng)歷吧(別問我什么是Instrument)

Apple的instrument為開發(fā)者提供了各種template去優(yōu)化app性能和定位問題捶索。很多公司都在趕feature,并沒有充足的時間來做優(yōu)化灰瞻,導(dǎo)致不少開發(fā)者對instrument不怎么熟悉腥例。但這里面其實涵蓋了非常完整的計算機基礎(chǔ)理論知識體系辅甥,memory,disk燎竖,network璃弄,thread,cpu构回,gpu等等夏块,順藤摸瓜去學習,是一筆巨大的知識財富纤掸。動畫性能只是其中一個template拨扶,重點還是理解上面問題當中CPU GPU如何配合工作的知識。

facebook啟動時間優(yōu)化

1.瘦身請求依賴
2.UDP啟動請求先行緩存
3.隊列串行化處理啟動響應(yīng)

以下文章可以做一個學習參考:
GCD面試要點
block面試要點
Runtime面試要點
RunLoop面試要點
內(nèi)存管理面試要點
MVC茁肠、MVVM面試要點
網(wǎng)絡(luò)性能優(yōu)化面試要點
網(wǎng)絡(luò)編程面試要點
KVC&KVO面試要點
數(shù)據(jù)存儲面試要點
混編技術(shù)面試要點
設(shè)計模式面試要點
UI面試要點

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市缩举,隨后出現(xiàn)的幾起案子垦梆,更是在濱河造成了極大的恐慌,老刑警劉巖仅孩,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件托猩,死亡現(xiàn)場離奇詭異,居然都是意外死亡辽慕,警方通過查閱死者的電腦和手機京腥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來溅蛉,“玉大人公浪,你說我怎么就攤上這事〈啵” “怎么了欠气?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長镜撩。 經(jīng)常有香客問我预柒,道長,這世上最難降的妖魔是什么袁梗? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任宜鸯,我火速辦了婚禮,結(jié)果婚禮上遮怜,老公的妹妹穿的比我還像新娘淋袖。我一直安慰自己,他們只是感情好锯梁,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布适贸。 她就那樣靜靜地躺著灸芳,像睡著了一般。 火紅的嫁衣襯著肌膚如雪拜姿。 梳的紋絲不亂的頭發(fā)上烙样,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天,我揣著相機與錄音蕊肥,去河邊找鬼谒获。 笑死,一個胖子當著我的面吹牛壁却,可吹牛的內(nèi)容都是我干的批狱。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼展东,長吁一口氣:“原來是場噩夢啊……” “哼赔硫!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起盐肃,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤爪膊,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后砸王,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體推盛,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年谦铃,在試婚紗的時候發(fā)現(xiàn)自己被綠了耘成。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡驹闰,死狀恐怖瘪菌,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情嘹朗,我是刑警寧澤控嗜,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站骡显,受9級特大地震影響疆栏,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜惫谤,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一壁顶、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧溜歪,春花似錦若专、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽膊爪。三九已至,卻和暖如春嚎莉,著一層夾襖步出監(jiān)牢的瞬間米酬,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工趋箩, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留赃额,地道東北人。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓叫确,卻偏偏與公主長得像跳芳,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子竹勉,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

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