性能優(yōu)化

UI卡頓優(yōu)化 :

1.?基于CPU和GPU兩方面來回答,盡可能減少CPU、GPU資源消耗

2.?按照60FPS的刷幀率,每隔16ms就會有一次VSync信號

3.?對象的創(chuàng)建會分配內(nèi)存、設置屬性等,會消耗CPU資源。所以盡量使用輕量對象代替,比如能用CALayer的時候盡量不用UIView,敏感位置能不用IB盡量使用純代碼手寫。

4.?不要頻繁地調(diào)用UIView的相關屬性,比如frame、bounds、transform等屬性,盡量減少不必要的修改

5.?盡量提前計算好布局,在有需要時一次性調(diào)整對應的屬性,不要多次修改屬性

6.?Autolayout會比直接設置frame消耗更多的CPU資源

7.?圖片的size最好剛好跟UIImageView的size保持一致

8.?控制一下線程的最大并發(fā)數(shù)量

9.?盡量把耗時的操作放到子線程

預渲染:10 11

10.?文本處理(尺寸計算、繪制)?

11.圖片處理(解碼、繪制)

12.?盡量避免短時間內(nèi)大量圖片的顯示,盡可能將多張圖片合成一張進行顯示

13.?GPU能處理的最大紋理尺寸是4096x4096,一旦超過這個尺寸,就會占用CPU資源進行處理,所以紋理盡量不要超過這個尺寸

14.?盡量減少視圖數(shù)量和層次

15.?減少透明的視圖(alpha<1),不透明的就設置opaque為YES

16.?盡量避免出現(xiàn)離屏渲染和圖層混合

17. 使用復用機制,View 的復用和懶加載機制

卡頓掉幀的原因:

在規(guī)定的時間之內(nèi)(16.7ms),在下一幀Vsync信號到來之前,CPU和GPU并沒有完成下一幀畫面的的合成 于是造成了掉幀 在滑動的時候就會有卡頓的現(xiàn)象?

卡頓掉幀檢測:

可以添加Observer到主線程RunLoop中,通過監(jiān)聽RunLoop狀態(tài)切換的耗時,以達到監(jiān)控卡頓的目的

內(nèi)存優(yōu)化:

1.? Cell的重用機制,包括UITableView、UICollectionView

2. 循環(huán)引用?

循環(huán)引用是iOS開發(fā)中經(jīng)常遇到的問題,尤其對于新手來說是個頭疼的問題。循環(huán)引用對App有潛在的危害,會使內(nèi)存消耗過高,性能變差和Crash等

3. Autoreleasepool的正確使用

4.?合理使用cache

如何計算圖片加載內(nèi)存中所占的大?。?/b>

圖片內(nèi)存大小的計算公式 寬度 * 高度 * bytesPerPixel/8。

bytesPerPixel : 每個像素所占的字節(jié)數(shù)。

RGBA顏色空間下 每個顏色分量由32位組成

所以一般圖片的計算公式是 寬度?x 高度?x 4

檢測工具:

1、Xcode Memory Debugger

2、Instruments?Analyse?Alloctions

3、MLeaksFinder

泄露的內(nèi)存主要有以下兩種:

Laek Memory 這種是忘記 Release 操作所泄露的內(nèi)存。

Abandon Memory 這種是循環(huán)引用,無法釋放掉的內(nèi)存。

耗電優(yōu)化:

1. 盡可能降低CPU、GPU功耗

2.?少用定時器

3.?優(yōu)化I/O操作,盡量不要頻繁寫入小數(shù)據(jù),最好批量一次性寫入

4.?數(shù)據(jù)量比較大的,建議使用數(shù)據(jù)庫(比如SQLite、CoreData)

5.?讀寫大量重要數(shù)據(jù)時,考慮用dispatch_io,其提供了基于GCD的異步操作文件I/O的API。用dispatch_io系統(tǒng)會優(yōu)化磁盤訪問

檢測:

Instrument Energy Diagnostics

網(wǎng)絡優(yōu)化:

1.?減少、壓縮網(wǎng)絡數(shù)據(jù)

2.?如果多次請求的結果是相同的,盡量使用緩存

3.?使用斷點續(xù)傳,否則網(wǎng)絡不穩(wěn)定時可能多次傳輸相同的內(nèi)容

4.?網(wǎng)絡不可用時,不要嘗試執(zhí)行網(wǎng)絡請求

5.?讓用戶可以取消長時間運行或者速度很慢的網(wǎng)絡操作,設置合適的超時時間

定位優(yōu)化:

1.?如果只是需要快速確定用戶位置,最好用CLLocationManager的requestLocation方法。定位完成后,會自動讓定位硬件斷電

2.?如果不是導航應用,盡量不要實時更新位置,定位完畢就關掉定位服務

3.?盡量降低定位精度,比如盡量不要使用精度最高的kCLLocationAccuracyBest

4.?需要后臺定位時,盡量設置pausesLocationUpdatesAutomatically為YES,如果用戶不太可能移動的時候系統(tǒng)會自動暫停位置更新

5.?盡量不要使用startMonitoringSignificantLocationChanges,優(yōu)先考慮startMonitoringForRegion:

APP的啟動:

啟動時間 = pre-main耗時+main耗時

應該在400ms內(nèi)完成main()函數(shù)之前的加載

整體過程耗時不能超過20秒,否則系統(tǒng)會kill掉進程,App啟動失敗

啟動前:

1. 盡量使用靜態(tài)庫,減少動態(tài)庫的使用,動態(tài)鏈接比較耗時,如果要用動態(tài)庫,盡量將多個dylib動態(tài)庫合并成一個

2. 盡量避免對系統(tǒng)庫使用optional linking,如果App用到的系統(tǒng)庫在你所有支持的系統(tǒng)版本上都有,就設置為required,因為optional會有些額外的檢查

3. 減少Objc類、分類的數(shù)量、減少Selector數(shù)量(定期清理不必要的類、分類)

4.?減少C++虛函數(shù)數(shù)量

5. 將不必須在+load中做的事情盡量挪到+initialize中,+initialize是在第一次初始化這個類之前被調(diào)用,+load在加載類的時候就被調(diào)用。盡量將+load里的代碼延后調(diào)用

6. 刪減一些無用的靜態(tài)變量,刪減沒有被調(diào)用到或者已經(jīng)廢棄的方法

7. 對application:didFinishLaunchingWithOptions:里的任務盡量延遲加載或懶加載

8. 不要在NSUserDefaults中存放太多的數(shù)據(jù),NSUserDefaults是一個plist文件,plist文件會被反序列化一次

9.?二進制文件重排優(yōu)化啟動速度? 基于Clang SanitizerCoverage 的工具 AppOrderFiles。CocoaPods 接入,一行調(diào)用生成 Order File。 GitHub地址:https://github.com/yulingtianxia/AppOrderFiles

安裝包瘦身:

1. 編寫LLVM插件檢測出重復代碼、未被調(diào)用的代碼

2.?去除沒有用到的資源:?https://github.com/tinymind/LSUnusedResources

3.?資源(圖片、音頻、視頻等)采取無損壓縮

使用Image Asset Catalogs,? Apple推薦的圖片資源管理工具,壓縮效率更高,在iOS 12的機器上有10~20%的空間節(jié)約,并且每個版本Apple都會持續(xù)對其進行優(yōu)化。

分為:

壓縮圖片質(zhì)量

一般情況下使用UIImageJPEGRepresentation或UIImagePNGRepresentation方法實現(xiàn)。

壓縮圖片尺寸

一般通過指定壓縮的大小對圖像進行重繪

4.?利用AppCode(https://www.jetbrains.com/objc/)檢測未使用的代碼:菜單欄 -> Code -> Inspect Code

代碼優(yōu)化:

(1) 頭文件導入的時候 最好使用向后導入

原因:

不在A的頭文件中引入B的頭文件,就不會一并引入B的全部內(nèi)容,這樣就減少了編譯時間。

可以避免循環(huán)引用:因為如果兩個類在自己的頭文件中都引入了對方的頭文件,那么就會導致其中一個類無法被正確編譯

(2) 去掉NSlog打印

(3) 通過LLVM檢測重復代碼未調(diào)用代碼

(4) 多用枚舉表示狀態(tài) 選項 狀態(tài)碼

(5) 多用類型常量 少用#define 預處理命令

(6) @implementation?不要寫在頭文件,尤其是這個頭文件可能被?import?到多個地方的情況下!??!

否則會影響 ①包體積 ②消息發(fā)送時間(尤其是高頻使用的類)

1. UITableView怎么優(yōu)化?(緩存高度,異步繪制,減少層級,hide,避免離屏渲染)

緩存高度:當我們創(chuàng)建frame模型的時候,計算出來cell的高度的時候,我們可以將cell的高度緩存到字典里面,以cell的indexpath和Identifier作為為key。

NSString *key = [[HeightCache shareHeightCache] makeKeyWithIdentifier:@"YwywProductGradeCell" indexPath:indexPath];

if ([[HeightCache shareHeightCache] existInCacheByKey:key]) {

? ? return [[HeightCache shareHeightCache] heightFromCacheWithKey:key];

}else{

? ? YwywProductGradeModelFrame *modelFrame = self.gradeArray[indexPath.row];

? ? [[HeightCache shareHeightCache] cacheHieght:modelFrame.cellHight key:key];

? ? return modelFrame.cellHight;

}

異步繪制、減少層級:

避免離屏渲染:只要不是同時使用邊框/邊框顏色以及圓角的時候,都可以使用layer直接設置。不會造成離屏渲染。

2. 如何定位項目中影響性能的地方?以及如何進行性能優(yōu)化?

3.

4.?AppDelegate如何瘦身?

5.App 啟動優(yōu)化策略?最好結合啟動流程來說(main()函數(shù)的執(zhí)行前后都分別說一下,知道多少說多少)

一個 App 的啟動時間從側面可以反映出這個 App 的質(zhì)量。啟動時間一般分為兩部分:Pre-main Time 和 Loading Time。Loading Time 指的是程序入口 main 函數(shù)到 AppDelegate 的applicationDidBecomeActive方法之間的耗時

6.容錯處理你們一般是注意哪些?

在團隊協(xié)作開發(fā)當中,由于每個團隊成員的水平不一,很難控制代碼的質(zhì)量,保證代碼的健壯性,經(jīng)常會發(fā)生由于后臺返回異常數(shù)據(jù)造成app崩潰閃退的情況,為了避免這樣的情況項目中做一些容錯處理,顯得格外重要,極大程度上降低了因為數(shù)據(jù)容錯不到位產(chǎn)生崩潰閃退的概率。

例如:

1.字典

2.數(shù)組;

3.野指針;

4.NSNull

等~

7.如果項目開始容錯處理沒做?如何防止攔截潛在的崩潰?

例:

1、category給類添加方法用來替換掉原本存在潛在崩潰的方法。

2、利用runtime方法交換技術,將系統(tǒng)方法替換成類添加的新方法。

3、利用異常的捕獲來防止程序的崩潰,并且進行相應的處理。

總結:

1、不要過分相信服務器返回的數(shù)據(jù)會永遠的正確。

2、在對數(shù)據(jù)處理上,要進行容錯處理,進行相應判斷之后再處理數(shù)據(jù),這是一個良好的編程習慣。

8.對于性能優(yōu)化的方案?

9.?App 網(wǎng)絡層有哪些優(yōu)化策略?

10.?

11.程序crash的原因有哪些?


12.如何捕獲異常?

13.如何檢測項目中的卡頓問題(比如假死)?

Core Animation,Instruments里的圖形性能問題的測試工具。

view debugging,Xcode 自帶的,視圖層級。

reveal,視圖層級。.

14.講如何將一張內(nèi)存極大的圖片可以像地圖一樣的加載出來(只說實現(xiàn)思路)

使用CATiledLayer加載大圖,tile layer設置一個縮放區(qū)域的集合和重繪閾值,讓scroll view在縮放時,繪制層根據(jù)這些區(qū)域和縮放閾值去重新繪制當前顯示的區(qū)域

15.?fps是怎么計算的?除了用cadisplay,還有什么方法嗎?

16.?leaks怎么實現(xiàn)?如何代碼實現(xiàn)監(jiān)聽僵尸對象?

17.?AppDelegate如何瘦身?

18.App 啟動優(yōu)化策略?最好結合啟動流程來說(main()函數(shù)的執(zhí)行前后都分別說一下,知道多少說多少)?

19.?你知道有哪些情況會導致app卡頓,分別可以用什么方法來避免?(知道多少說多少)

20.App 網(wǎng)絡層有哪些優(yōu)化策略?

21.什么是離屏渲染?什么情況下會觸發(fā)?怎么檢測?該如何應對?

GPU屏幕渲染有兩種方式:

(1)On-Screen Rendering (當前屏幕渲染)?

指的是GPU的渲染操作是在當前用于顯示的屏幕緩沖區(qū)進行。

(2)Off-Screen Rendering (離屏渲染)

指的是在GPU在當前屏幕緩沖區(qū)以外開辟一個緩沖區(qū)進行渲染操作。

當前屏幕渲染不需要額外創(chuàng)建新的緩存,也不需要開啟新的上下文,相對于離屏渲染性能更好。但是受當前屏幕渲染的局限因素限制(只有自身上下文、屏幕緩存有限等),當前屏幕渲染有些情況下的渲染解決不了的,就使用到離屏渲染。

相比于當前屏幕渲染,離屏渲染的代價是很高的,主要體現(xiàn)在兩個方面:

(1)創(chuàng)建新緩沖區(qū)

要想進行離屏渲染,首先要創(chuàng)建一個新的緩沖區(qū)。

(2)上下文切換

離屏渲染的整個過程,需要多次切換上下文環(huán)境:先是從當前屏幕(On-Screen)切換到離屏(Off-Screen),等到離屏渲染結束以后,將離屏緩沖區(qū)的渲染結果顯示到屏幕上有需要將上下文環(huán)境從離屏切換到當前屏幕。而上下文環(huán)境的切換是要付出很大代價的。

下面的情況或操作會引發(fā)離屏渲染:

- 為圖層設置遮罩(layer.mask)

-?設置圓角時,將圖層的layer.masksToBounds / view.clipsToBounds屬性設置為true?

-?將圖層layer.allowsGroupOpacity屬性設置為YES和layer.opacity小于1.0

-?為圖層設置陰影(layer.shadow *)。

-?為圖層設置layer.shouldRasterize=true

-?具有l(wèi)ayer.cornerRadius,layer.edgeAntialiasingMask,layer.allowsEdgeAntialiasing的圖層

-?文本(任何種類,包括UILabel,CATextLayer,Core Text等)。

-?使用CGContext在drawRect :方法中繪制大部分情況下會導致離屏渲染,甚至僅僅是一個空的實現(xiàn)。

優(yōu)化方案

官方對離屏渲染產(chǎn)生性能問題也進行了優(yōu)化:

iOS 9.0 之前UIimageView跟UIButton設置圓角都會觸發(fā)離屏渲染。

iOS 9.0 之后UIButton設置圓角會觸發(fā)離屏渲染,而UIImageView里png圖片設置圓角不會觸發(fā)離屏渲染了,如果設置其他陰影效果之類的還是會觸發(fā)離屏渲染的。

1、圓角優(yōu)化

優(yōu)化方案1:使用貝塞爾曲線UIBezierPath和Core Graphics框架畫出一個圓角

UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(100,100,100,100)];

imageView.image = [UIImage imageNamed:@"myImg"];

//開始對imageView進行畫圖

UIGraphicsBeginImageContextWithOptions(imageView.bounds.size,NO,1.0);

//使用貝塞爾曲線畫出一個圓形圖

[[UIBezierPath bezierPathWithRoundedRect:imageView.boundscornerRadius:imageView.frame.size.width]addClip];

[imageView drawRect:imageView.bounds];

imageView.image=UIGraphicsGetImageFromCurrentImageContext();

//結束畫圖

UIGraphicsEndImageContext();

[self.view addSubview:imageView];

優(yōu)化方案2:使用CAShapeLayer和UIBezierPath設置圓角

UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(100, 100, 100, 100)];

imageView.image = [UIImage imageNamed:@"myImg"];

UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:imageView.bounds byRoundingCorners:UIRectCornerAllCorners cornerRadii:imageView.bounds.size];

CAShapeLayer *maskLayer = [[CAShapeLayer alloc]init];

//設置大小

maskLayer.frame = imageView.bounds;

//設置圖形樣子

maskLayer.path = maskPath.CGPath;

imageView.layer.mask = maskLayer;

[self.view addSubview:imageView];

對于方案2需要解釋的是:

CAShapeLayer繼承于CALayer,可以使用CALayer的所有屬性值;

CAShapeLayer需要貝塞爾曲線配合使用才有意義(也就是說才有效果)

使用CAShapeLayer(屬于CoreAnimation)與貝塞爾曲線可以實現(xiàn)不在view的drawRect(繼承于CoreGraphics走的是CPU,消耗的性能較大)方法中畫出一些想要的圖形

CAShapeLayer動畫渲染直接提交到手機的GPU當中,相較于view的drawRect方法使用CPU渲染而言,其效率極高,能大大優(yōu)化內(nèi)存使用情況。

總的來說就是用CAShapeLayer的內(nèi)存消耗少,渲染速度快,建議使用優(yōu)化方案2。

3、其他的一些優(yōu)化建議

當我們需要圓角效果時,可以使用一張中間透明圖片蒙上去

使用ShadowPath指定layer陰影效果路徑

使用異步進行l(wèi)ayer渲染(Facebook開源的異步繪制框架AsyncDisplayKit)

設置layer的opaque值為YES,減少復雜圖層合成

盡量使用不包含透明(alpha)通道的圖片資源

盡量設置layer的大小值為整形值

直接讓美工把圖片切成圓角進行顯示,這是效率最高的一種方案

很多情況下用戶上傳圖片進行顯示,可以讓服務端處理圓角

使用代碼手動生成圓角Image設置到要顯示的View上,利用UIBezierPath(CoreGraphics框架)畫出來圓角圖片

Core Animation工具檢測離屏渲染

對于離屏渲染的檢測,蘋果為我們提供了一個測試工具Core Animation??梢栽赬code->Open Develeper Tools->Instruments中找到

下面我們來說明每個選項的功能:

Color Blended Layers:這個選項如果勾選,你能看到哪個layer是透明的,GPU正在做混合計算。顯示紅色的就是透明的,綠色就是不透明的。

Color Hits Green and Misses Red:如果勾選這個選項,且當我們代碼中有設置shouldRasterize為YES,那么紅色代表沒有復用離屏渲染的緩存,綠色則表示復用了緩存。我們當然希望能夠復用。

Color Copied Images:按照官方的說法,當圖片的顏色格式GPU不支持的時候,Core Animation會

Color Immediately:默認情況下Core Animation工具以每毫秒10次的頻率更新圖層調(diào)試顏色,如果勾選這個選項則移除10ms的延遲。對某些情況需要這樣,但是有可能影響正常幀數(shù)的測試。

Color Misaligned Images:勾選此項,如果圖片需要縮放則標記為黃色,如果沒有像素對齊則標記為紫色。像素對齊我們已經(jīng)在上面有所介紹。

Color Offscreen-Rendered Yellow:用來檢測離屏渲染的,如果顯示黃色,表示有離屏渲染。當然還要結合Color Hits Green and Misses Red來看,是否復用了緩存。

Color OpenGL Fast Path Blue:這個選項對那些使用OpenGL的圖層才有用,像是GLKView或者 CAEAGLLayer,如果不顯示藍色則表示使用了CPU渲染,繪制在了屏幕外,顯示藍色表示正常。

Flash Updated Regions:當對圖層重繪的時候回顯示黃色,如果頻繁發(fā)生則會影響性能。可以用增加緩存來增強性能。

CPU處理,Processing

網(wǎng)絡,Networking

定位,Location

圖像,Graphics

22.?怎么檢測圖層混合?

怎么檢測圖層混合

1、模擬器debug中color blended layers紅色區(qū)域表示圖層發(fā)生了混合

2、Instrument-選中Core Animation-勾選Color Blended Layers

避免圖層混合:

確保控件的opaque屬性設置為true,確保backgroundColor和父視圖顏色一致且不透明

如無特殊需要,不要設置低于1的alpha值

確保UIImage沒有alpha通道

UILabel圖層混合解決方法:

iOS8以后設置背景色為非透明色并且設置label.layer.masksToBounds=YES讓label只會渲染她的實際size區(qū)域,就能解決UILabel的圖層混合問題

iOS8 之前只要設置背景色為非透明的就行

為什么設置了背景色但是在iOS8上仍然出現(xiàn)了圖層混合呢?

UILabel在iOS8前后的變化,在iOS8以前,UILabel使用的是CALayer作為底圖層,而在iOS8開始,UILabel的底圖層變成了_UILabelLayer,繪制文本也有所改變。在背景色的四周多了一圈透明的邊,而這一圈透明的邊明顯超出了圖層的矩形區(qū)域,設置圖層的masksToBounds為YES時,圖層將會沿著Bounds進行裁剪 圖層混合問題解決了

23.?

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

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