在性能優(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面試要點