性能優(yōu)化是一個大的問題,所以首先是需要把這個問題分而化之,把它分解成一個個影響app性能的小問題才能進(jìn)行回答,所以在這里做出一些整理來回答這個問題,同時也提醒自己再次遇到如此大的問題時學(xué)會分析問題的本身以及從哪些方面去回答這些問題榨乎。
影響app性能的幾個問題有:
1. 網(wǎng)絡(luò)性能
網(wǎng)絡(luò)性能優(yōu)化涉及到DNS解析,路由算法棠涮,以及服務(wù)器端性能谬哀,不是很了解,可參看一下文章:
攜程App的網(wǎng)絡(luò)性能優(yōu)化實踐
影響移動應(yīng)用網(wǎng)絡(luò)性能的三大因素
2. 內(nèi)存問題
在MRC時代严肪,手動釋放內(nèi)存會導(dǎo)致大量內(nèi)存的泄露史煎。但是在ARC時代解決了大部分的內(nèi)存泄露,但是仍然會出現(xiàn)內(nèi)存泄露的問題:
1. 循環(huán)引用
2. Core Animation對象手動釋放
3. UIWebView內(nèi)存泄露
一些詳細(xì)介紹如下:
ARC下的內(nèi)存泄漏
ARC 下內(nèi)存泄露的那些點
3. 主線程阻塞
所有的用戶輸入和UIKit的渲染是在主線程執(zhí)行驳糯。所以要保證app的流暢度就一定不能阻塞主線程篇梭,把可以在子線程中做的事放到子線程中來減少主線程的計算與處理。
假如在主線程中執(zhí)行如下操作:
1. 網(wǎng)絡(luò)同步請求
2. I/O操作
3. 大量運(yùn)算
4. 解壓縮
...
因為需要處理的多所以會阻塞主線程酝枢,導(dǎo)致卡頓恬偷,因此要減少主線程中耗時的操作,使用多線程(NSThread帘睦、NSOperationQueue, GCD)來處理這些袍患。可以查看OS X 和 iOS 中的多線程技術(shù)關(guān)于多線程的介紹竣付。還有主線程關(guān)于渲染的處理會影響效率诡延,所以這一塊也是需要處理的。
4. Offscreen rendering(離屏渲染)
離屏渲染古胆,指的是GPU在當(dāng)前屏幕緩沖區(qū)以外新開辟一個緩沖區(qū)進(jìn)行渲染操作肆良。離屏渲染意味著你App的部分區(qū)域每一幀渲染了兩次。所以會造成一定的性能損失逸绎。
對于UIView或者CALayer的frame,bounds,transform等屬性的改變惹恃,消耗的資源遠(yuǎn)大于他們其他的屬性改變。
可以參考以下文章:
繪制像素到屏幕上
繪制陰影引發(fā)的 iOS 繪圖性能問題總結(jié)
iOS 離屏渲染的研究
5. 圖片的處理
通常會用imageNamed:來加載mainbundle中的圖片棺牧,此函數(shù)會緩存加載的image巫糙。因此,對于那些被重用的圖片陨帆,這個API很高效曲秉。但是對于那些使用很少的圖片采蚀,用這個就很耗內(nèi)存疲牵。
所以在加載使用一次的應(yīng)用圖片時使用initWithContentsOfFile:函數(shù)承二,而在加載多次使用的圖片時就使用imageNamed:函數(shù)。例如加載引導(dǎo)頁的圖片時使用載入路徑的方式纲爸,而使用通用的背景圖的就使用imageNamed:的方式亥鸠。
//使用路徑方式載入圖片
NSString *path = [[NSBundle mainBundle] pathForResource:fileName ofType:fileType];
UIImage *image = [[UIImage alloc] initWithContentsOfFile:path];
//使用圖片名的方式載入圖片
UIImage *image = [UIImage imageNamed:fileName];
或
//讀取本地圖片的 和imageNamed一樣,但是性能比后者要強(qiáng)很多识啦,兩個參數(shù)负蚊,前面一個是 文件名,后面一個是類型
#define LoadImage(_pointer) [UIImage imageNamed:[UIUtil imageName:_pointer]] //可以用來直接傳圖片名字
#define LoadImageWithType(file,ext) [UIImage imageWithContentsOfFile:[[NSBundle mainBundle]pathForResource:file ofType:ext]]
一般的優(yōu)化技術(shù)就是在減少內(nèi)存使用颓哮,減少主線程業(yè)務(wù)處理家妆,用空間來換時間等等,基于這些策略及技術(shù)考慮來選擇優(yōu)化方向冕茅。
以下是iOS的一些細(xì)節(jié)優(yōu)化策略
- 避免對UIView使用透明伤极。(UIView默認(rèn)是非透明)。原因是透明對性能要求較高姨伤,如果在滾動時頁面比較復(fù)雜哨坪,體驗上的差異會相對明顯。
- 避免過于龐大的xib乍楚。(如果不得不使用一個ViewController作為xib,也應(yīng)該將其其中的子視圖拆成小的xib)当编。
需要注意的是,當(dāng)你加載一個XIB的時候所有內(nèi)容都被放在了內(nèi)存里徒溪,包括任何圖片忿偷。如果有一個不會即刻用到的view,你這就是在浪費寶貴的內(nèi)存資源了臊泌。Storyboards就是另一碼事兒了鲤桥,storyboard僅在需要時實例化一個view controller.
不要阻塞主線程。
- 使圖片符合UIImageView的尺寸缺虐。不要在運(yùn)行的時候再讓UIImageView自行壓縮芜壁,因為這樣會降低運(yùn)行時的性能。(注:手動壓縮圖片的方法高氮,在context中使用drawInRect)
- 選擇合適的collection慧妄,數(shù)據(jù)結(jié)構(gòu)決定了算法的效率。 如:Array使用下標(biāo)查找較快剪芍,但插入和刪除較慢塞淹。set進(jìn)行插入和刪除很快。
- 使用緩存罪裹,因為數(shù)據(jù)具有時效的饱普,所以對于時效性要求不高的數(shù)據(jù)完全可以使用緩存來保證快速顯示运挫。例如URL對應(yīng)的圖片緩存(SDWebImage),通過數(shù)據(jù)庫活core Data來保存不需要變動的數(shù)據(jù)套耕,UIWeb的緩存等都屬于這種谁帕。
- 處理低內(nèi)存警告。在收到內(nèi)存警告時冯袍,清除對cache的強(qiáng)引用匈挖,沒有當(dāng)前顯示需要的image,以及一些其他可以再創(chuàng)建的對象康愤。
- 重用一些高消耗的對象儡循,如NSDateFormatter、NSCalender等征冷。解決方法:可以將其作為property择膝、甚至是靜態(tài)變量作為單例在APP中使用。并且检激,NSDateFormatter的 setDateFormate也是非常消耗資源的一個操作肴捉。
- 網(wǎng)絡(luò)傳輸過來的數(shù)據(jù),往往是json或xml字符串呵扛。直接將這些字符串轉(zhuǎn)換成我們需要的數(shù)據(jù)結(jié)構(gòu)(自定義類或者NSDictionary),避免后續(xù)使用的時候還要做數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)換產(chǎn)生不必要的消耗每庆。
- 設(shè)置UIView的背景圖片時,如果是整幅圖今穿,就采用addSubView一個UIImageView缤灵;如果是要重復(fù)平鋪一個小圖,就使用colorWithPatternImage蓝晒,因為這個函數(shù)的設(shè)計上就是針對小圖的腮出,如果用于整幅大圖來做背景,反而會消耗更多內(nèi)存芝薇。
- 在臨時創(chuàng)建大量對象時胚嘲,使用NSAutoreleasepool,例如洛二,一個循環(huán)用于創(chuàng)建包含多個對象的數(shù)組馋劈,在循環(huán)體內(nèi),即可使用@autoreleasepool包裹創(chuàng)建代碼晾嘶。使用系統(tǒng)的@autoreleasepool會有延遲妓雾,內(nèi)存不會馬上釋放。
- 對于排版復(fù)雜的文字或者圖文混排垒迂,使用CoreText技術(shù)械姻。(而不是一味地堆UILabel)
- 在對渲染的效率要求較高的頁面中,避免使用UILabel机断、UITextView等在主線程中進(jìn)行排版和繪制的控件楷拳。應(yīng)自定義文本控件绣夺,用TextKit或者CoreText進(jìn)行文本異步繪制舆逃。另外酝陈,還有facebook的AsyncDisplayKit框架可以采用。
將繪制圖像放在次線程中執(zhí)行奋渔,如在次線程中使用 CGContext進(jìn)行畫圖浸颓,在主線程中 layer.contents = img物臂。
圖片和視圖的大小避免超過4096*4096旺拉,因為這是目前iphone5到iphone6p以及ipad僅僅通過GPU就直接處理的紋理尺寸上限产上,否則就GPU就會提交CPU先處理,這樣開銷很大蛾狗。
- 減少視圖或者layer的層級數(shù)量晋涣,在有多個層級時,可以將多圖合并成一張圖沉桌,再渲染顯示谢鹊。
- 電量消耗:減少耗電與流量的操作。GPS在獲取用戶位置之后留凭,就進(jìn)行關(guān)閉佃扼,因為它非常耗電。
- 關(guān)于后臺運(yùn)行蔼夜。進(jìn)入后臺后兼耀,即盡量減少內(nèi)存占用、釋放所有的共享資源(如Calender或address book)求冷,因為iOS會kill后臺中內(nèi)存消耗最多的或者進(jìn)入后臺還占用共享資源的進(jìn)程瘤运。
參考文章:
iOS App性能優(yōu)化
讓App的運(yùn)行速度與響應(yīng)速度趨于一流
程序猿進(jìn)化必讀:讓App的運(yùn)行速度與響應(yīng)速度趨于一流(iOS)
iOS應(yīng)用性能調(diào)優(yōu)的4個建議和技巧