在性能優(yōu)化中一個(gè)最具參考價(jià)值的屬性是FPS:Frames Per Second,其實(shí)就是屏幕刷新率,蘋(píng)果的iphone推薦的刷新率是60Hz,也就是說(shuō)GPU每秒鐘刷新屏幕60次植阴,這每刷新一次就是一幀frame捧搞,F(xiàn)PS也就是每秒鐘刷新多少幀畫(huà)面。靜止不變的頁(yè)面FPS值是0健民,這個(gè)值是沒(méi)有參考意義的抒巢,只有當(dāng)頁(yè)面在執(zhí)行動(dòng)畫(huà)或者滑動(dòng)的時(shí)候,F(xiàn)PS值才具有參考價(jià)值秉犹,F(xiàn)PS值的大小體現(xiàn)了頁(yè)面的流暢程度高低蛉谜,當(dāng)?shù)陀?5的時(shí)候卡頓會(huì)比較明顯。
圖層混合:
每一個(gè)layer是一個(gè)紋理崇堵,所有的紋理都以某種方式堆疊在彼此的頂部型诚。對(duì)于屏幕上的每一個(gè)像素,GPU需要算出怎么混合這些紋理來(lái)得到像素RGB的值鸳劳。
當(dāng)Sa = 0.5時(shí)狰贯,RGB值為(0.5, 0, 0),可以看出赏廓,當(dāng)兩個(gè)不是完全不透明的CALayer覆蓋在一起時(shí),GPU大量做這種復(fù)合操作涵紊,隨著這中操作的越多,GPU越忙碌幔摸,性能肯定會(huì)受到影響摸柄。
公式:
R = S + D * ( 1 – Sa )
結(jié)果的顏色是源色彩(頂端紋理)+目標(biāo)顏色(低一層的紋理)*(1-源顏色的透明度)。
當(dāng)Sa = 1時(shí)既忆,R = S,GPU將不會(huì)做任何合成驱负,而是簡(jiǎn)單從這個(gè)層拷貝嗦玖,不需要考慮它下方的任何東西(因?yàn)槎急凰趽踝×?,這節(jié)省了GPU相當(dāng)大的工作量电媳。
一踏揣、入門(mén)級(jí)
1、用ARC管理內(nèi)存 2匾乓、在正確的地方使用 reuseIdentifier 3捞稿、盡量把views設(shè)置為透明 4、避免過(guò)于龐大的XIB 5拼缝、不要阻塞主線程
6娱局、在ImageViews中調(diào)整圖片大小。如果要在UIImageView中顯示一個(gè)來(lái)自bundle的圖片咧七,你應(yīng)保證圖片的大小和UIImageView的大小相同衰齐。在運(yùn)行中縮放圖片是很耗費(fèi)資源的,特別是UIImageView嵌套在UIScrollView中的情況下继阻。如果圖片是從遠(yuǎn)端服務(wù)加載的你不能控制圖片大小耻涛,比如在下載前調(diào)整到合適大小的話,你可以在下載完成后瘟檩,最好是用background thread抹缕,縮放一次,然后在UIImageView中使用縮放后的圖片墨辛。
7卓研、選擇正確的Collection。
Arrays: 有序的一組值睹簇。使用index來(lái)lookup很快奏赘,使用value lookup很慢, 插入/刪除很慢太惠。
Dictionaries: 存儲(chǔ)鍵值對(duì)磨淌。 用鍵來(lái)查找比較快。
Sets: 無(wú)序的一組值凿渊。用值來(lái)查找很快梁只,插入/刪除很快。
8嗽元、打開(kāi)gzip壓縮敛纲。app可能大量依賴于服務(wù)器資源,問(wèn)題是我們的目標(biāo)是移動(dòng)設(shè)備剂癌,因此你就不能指望網(wǎng)絡(luò)狀況有多好淤翔。減小文檔的一個(gè)方式就是在服務(wù)端和你的app中打開(kāi)gzip。這對(duì)于文字這種能有更高壓縮率的數(shù)據(jù)來(lái)說(shuō)會(huì)有更顯著的效用佩谷。 iOS已經(jīng)在NSURLConnection中默認(rèn)支持了gzip壓縮旁壮,當(dāng)然AFNetworking這些基于它的框架亦然监嗜。
二、中級(jí)
1抡谐、重用和延遲加載(lazy load) Views
更多的view意味著更多的渲染裁奇,也就是更多的CPU和內(nèi)存消耗,對(duì)于那種嵌套了很多view在UIScrollView里邊的app更是如此麦撵。
這里我們用到的技巧就是模仿UITableView和UICollectionView的操作: 不要一次創(chuàng)建所有的subview刽肠,而是當(dāng)需要時(shí)才創(chuàng)建,當(dāng)它們完成了使命免胃,把他們放進(jìn)一個(gè)可重用的隊(duì)列中音五。這樣的話你就只需要在滾動(dòng)發(fā)生時(shí)創(chuàng)建你的views,避免了不劃算的內(nèi)存分配羔沙。
2躺涝、Cache, Cache, 還是Cache!
一個(gè)極好的原則就是,緩存所需要的扼雏,也就是那些不大可能改變但是需要經(jīng)常讀取的東西坚嗜。
我們能緩存些什么呢?一些選項(xiàng)是诗充,遠(yuǎn)端服務(wù)器的響應(yīng)苍蔬,圖片,甚至計(jì)算結(jié)果其障,比如UITableView的行高银室。
NSCache和NSDictionary類似涂佃,不同的是系統(tǒng)回收內(nèi)存的時(shí)候它會(huì)自動(dòng)刪掉它的內(nèi)容励翼。
3、權(quán)衡渲染方法.性能能還是要bundle保持合適的大小辜荠。
4汽抚、處理內(nèi)存警告.移除對(duì)緩存,圖片object和其他一些可以重創(chuàng)建的objects的strong references.
5伯病、重用大開(kāi)銷(xiāo)對(duì)象
6造烁、一些objects的初始化很慢,比如NSDateFormatter和NSCalendar午笛。然而惭蟋,你又不可避免地需要使用它們,比如從JSON或者XML中解析數(shù)據(jù)药磺。想要避免使用這個(gè)對(duì)象的瓶頸你就需要重用他們告组,可以通過(guò)添加屬性到你的class里或者創(chuàng)建靜態(tài)變量來(lái)實(shí)現(xiàn)。
7癌佩、避免反復(fù)處理數(shù)據(jù).在服務(wù)器端和客戶端使用相同的數(shù)據(jù)結(jié)構(gòu)很重要木缝。
8便锨、選擇正確的數(shù)據(jù)格式.解析JSON會(huì)比XML更快一些,JSON也通常更小更便于傳輸我碟。從iOS5起有了官方內(nèi)建的JSON deserialization 就更加方便使用了放案。但是XML也有XML的好處,比如使用SAX 來(lái)解析XML就像解析本地文件一樣矫俺,你不需像解析json一樣等到整個(gè)文檔下載完成才開(kāi)始解析吱殉。當(dāng)你處理很大的數(shù)據(jù)的時(shí)候就會(huì)極大地減低內(nèi)存消耗和增加性能。
9厘托、正確設(shè)定背景圖片
全屏背景圖考婴,在view中添加一個(gè)UIImageView作為一個(gè)子View
只是某個(gè)小的view的背景圖,你就需要用UIColor的colorWithPatternImage來(lái)做了催烘,它會(huì)更快地渲染也不會(huì)花費(fèi)很多內(nèi)存:
10沥阱、減少使用Web特性。想要更高的性能你就要調(diào)整下你的HTML了伊群。第一件要做的事就是盡可能移除不必要的javascript考杉,避免使用過(guò)大的框架。能只用原生js就更好了舰始。盡可能異步加載例如用戶行為統(tǒng)計(jì)script這種不影響頁(yè)面表達(dá)的javascript崇棠。注意你使用的圖片,保證圖片的符合你使用的大小丸卷。
11枕稀、Shadow Path 。CoreAnimation不得不先在后臺(tái)得出你的圖形并加好陰影然后才渲染谜嫉,這開(kāi)銷(xiāo)是很大的萎坷。使用shadowPath的話就避免了這個(gè)問(wèn)題。使用shadow path的話iOS就不必每次都計(jì)算如何渲染沐兰,它使用一個(gè)預(yù)先計(jì)算好的路徑哆档。但問(wèn)題是自己計(jì)算path的話可能在某些View中比較困難,且每當(dāng)view的frame變化的時(shí)候你都需要去update shadow path.
12住闯、優(yōu)化Table View
正確使用reuseIdentifier來(lái)重用cells
盡量使所有的view opaque瓜浸,包括cell自身
避免漸變,圖片縮放比原,后臺(tái)選人
緩存行高
如果cell內(nèi)現(xiàn)實(shí)的內(nèi)容來(lái)自web插佛,使用異步加載,緩存請(qǐng)求結(jié)果
使用shadowPath來(lái)畫(huà)陰影
減少subviews的數(shù)量
盡量不適用cellForRowAtIndexPath:量窘,如果你需要用到它雇寇,只用-一次然后緩存結(jié)果
使用正確的數(shù)據(jù)結(jié)構(gòu)來(lái)存儲(chǔ)數(shù)據(jù)
使用rowHeight, sectionFooterHeight 和 sectionHeaderHeight來(lái)設(shè)定固定的高,不要請(qǐng)求delegate
13、選擇正確的數(shù)據(jù)存儲(chǔ)選項(xiàng)
NSUserDefaults的問(wèn)題是什么谢床?雖然它很nice也很便捷兄一,但是它只適用于小數(shù)據(jù),比如一些簡(jiǎn)單的布爾型的設(shè)置選項(xiàng)识腿,再大點(diǎn)你就要考慮其它方式了
XML這種結(jié)構(gòu)化檔案呢出革?總體來(lái)說(shuō),你需要讀取整個(gè)文件到內(nèi)存里去解析渡讼,這樣是很不經(jīng)濟(jì)的骂束。使用SAX又是一個(gè)很麻煩的事情。
NSCoding成箫?不幸的是展箱,它也需要讀寫(xiě)文件,所以也有以上問(wèn)題蹬昌。
在這種應(yīng)用場(chǎng)景下混驰,使用SQLite 或者 Core Data比較好。使用這些技術(shù)你用特定的查詢語(yǔ)句就能只加載你需要的對(duì)象皂贩。
在性能層面來(lái)講栖榨,SQLite和Core Data是很相似的。他們的不同在于具體使用方法明刷。
Core Data代表一個(gè)對(duì)象的graph model婴栽,但SQLite就是一個(gè)DBMS。
Apple在一般情況下建議使用Core Data辈末,但是如果你有理由不使用它愚争,那么就去使用更加底層的SQLite吧。
如果你使用SQLite挤聘,你可以用FMDB這個(gè)庫(kù)來(lái)簡(jiǎn)化SQLite的操作轰枝,這樣你就不用花很多經(jīng)歷了解SQLite的C API了。
三檬洞、高級(jí)
1狸膏、加速啟動(dòng)時(shí)間沟饥√碚快速打開(kāi)app是很重要的,特別是用戶第一次打開(kāi)它時(shí)贤旷,對(duì)app來(lái)講广料,第一印象太太太重要了。你能做的就是使它盡可能做更多的異步任務(wù)幼驶,比如加載遠(yuǎn)端或者數(shù)據(jù)庫(kù)數(shù)據(jù)艾杏,解析數(shù)據(jù)。避免過(guò)于龐大的XIB盅藻,因?yàn)樗麄兪窃谥骶€程上加載的购桑。所以盡量使用沒(méi)有這個(gè)問(wèn)題的Storyboards吧畅铭!一定要把設(shè)備從Xcode斷開(kāi)來(lái)測(cè)試啟動(dòng)速度
2、使用Autorelease Pool勃蜘。NSAutoreleasePool`負(fù)責(zé)釋放block中的autoreleased objects硕噩。一般情況下它會(huì)自動(dòng)被UIKit調(diào)用。但是有些狀況下你也需要手動(dòng)去創(chuàng)建它缭贡。假如你創(chuàng)建很多臨時(shí)對(duì)象炉擅,你會(huì)發(fā)現(xiàn)內(nèi)存一直在減少直到這些對(duì)象被release的時(shí)候。這是因?yàn)橹挥挟?dāng)UIKit用光了autorelease pool的時(shí)候memory才會(huì)被釋放阳惹。消息是你可以在你自己的@autoreleasepool里創(chuàng)建臨時(shí)的對(duì)象來(lái)避免這個(gè)行為谍失。
3、選擇是否緩存圖片莹汤。常見(jiàn)的從bundle中加載圖片的方式有兩種快鱼,一個(gè)是用imageNamed,二是用imageWithContentsOfFile纲岭,第一種比較常見(jiàn)一點(diǎn)攒巍。
4、避免日期格式轉(zhuǎn)換荒勇。如果你要用NSDateFormatter來(lái)處理很多日期格式柒莉,應(yīng)該小心以待。就像先前提到的沽翔,任何時(shí)候重用NSDateFormatters都是一個(gè)好的實(shí)踐兢孝。如果你可以控制你所處理的日期格式,盡量選擇Unix時(shí)間戳仅偎。你可以方便地從時(shí)間戳轉(zhuǎn)換到NSDate: