[TOC]
基礎優(yōu)化方向
使用 ARC 管理內(nèi)存
-
在正確的地方使用 reuseIdentifier
- tableview 用 tableView:cellForRowAtIndexPath: 為 rows 分配 cells 的時候眶俩,他的數(shù)據(jù)應該重用自 UITableViewCell
盡量將 views 設置為不透明(Opaque)
避免過于龐大的 XIB
-
不要阻塞主線程
用于不要是主線程承擔過多。因為UIKit在主線程上做所有工作谷市,
渲染亿蒸、管理觸摸反應、回應輸入等都需要在主線程上完成
-
大部分阻礙主線程的情形是你的APP在做一些涉及到讀寫外部資源的 I/O 操作沧竟,比如存儲或者網(wǎng)絡:
-
不要在 viewWillAppear 中做費時的操作
- viewWillAppear前翎,在 view 顯示之前被調(diào)用杆融,處于效率考慮燃乍,方法中不要處理復雜費時操作唆樊。
- 只能在該方法中設置 view 的顯示屬性之類的簡單事情,例如背景色刻蟹、字體等逗旁。否則,會明顯感覺到 view 有卡頓或者延遲舆瘪。
圖片處理
在 ImageView 中調(diào)整圖片大小片效。
-
保證圖片大小和 UIImageView 大小相同。
如果要在 UIIImageView 中顯示一個來自 bundle 的圖片英古,你應保證圖片的大小和 UIImageView 大小相同淀衣。
在運行中縮放圖片是耗費資源的,特別是 UIImageView 嵌套在 UIScrollView 中的情況下哺呜。
處理網(wǎng)絡圖片舌缤。如果圖片是從遠端服務器加載的,你無法控制圖片大小某残。那么就在下載完成之后国撵,最好是在
background thread
中,縮放一次玻墅,然后在 UIImageView 中使用縮放之后的圖片介牙。
-
imageNamed 初始化:加載圖片、并緩存
- imageNamed 默認加載圖片成功后澳厢,內(nèi)存中會緩存圖片环础。
- 這個方法用一個指定的名字在系統(tǒng)緩存中查找并返回一個圖片對象。
- 如果緩存中沒有找到響應的圖片對象剩拢,則從指定地方加載圖片线得,然后緩存對象,并返回這個而圖片對象徐伐。
-
imageWithContentsOfFile 初始化
- imageWithContentOfFile 則僅只加載贯钩、不緩存。
- 如果加載一張大圖并且使用一次办素,用 imageWithContentsOfFile 是最好的角雷,這樣 CPU 不需要做緩存,可以節(jié)約時間性穿。
-
具體使用哪一種需要根據(jù)應用場景加以區(qū)分勺三,UIImage 雖小,但是是使用非常多的元素需曾,也會有比較顯著的問題吗坚。
- “不以善小而不為,不以惡小而為之”
- “不積跬步無以至千里”
-
UIImageView
- 在性能的范圍之內(nèi)胯舷,直接對 UIImageView 設置圓角是不會觸發(fā)離屏渲染的刻蚯,但同時給 UIImageView 設置背景色肯定會觸發(fā)離屏渲染
- 觸發(fā)離屏渲染跟 .png.jpg 格式無關
UITableView 優(yōu)化
view相關操作
- 正確使用 reuseIdentifier 來重用 cells
- 減少subview的數(shù)量
- 盡量使所有的 view opaque(不透明),包括cell自身
- 使用 shadowPath 來畫陰影
- 避免漸變桑嘶、圖片縮放
緩存相關操作
- 緩存行高
- 盡量不要使用 cellForRowAtIndexPath炊汹。如果要使用,只用一次逃顶,然后緩存結果
- 盡量使用 rowHeight讨便、sectionHeight、sectionHeaderHeight 來設定固定的行高以政,不要請求delegate
數(shù)據(jù)加載相關操作
- 如果 cell 內(nèi)實現(xiàn)的內(nèi)容來自 web霸褒,使用異步加載,緩存請求結果
- 使用正確的數(shù)據(jù)結果來存儲數(shù)據(jù)
CPU 和 GPU 層優(yōu)化
本質上是降低 CPU盈蛮、GPU的工作废菱,從這兩個方面入手去提升性能
-
CPU做了什么事
- 邏輯運算
- 對象的創(chuàng)建
- 對象屬性的調(diào)整、布局計算、文本的計算和排版
- 圖片的格式轉碼和解碼
- 圖像的繪制
-
GPU做了什么事
- 數(shù)學運算
- 紋理繪制
CPU 層面的優(yōu)化
- 盡量用輕量級的對象殊轴,比如用不到時間處理的地方衰倦,可以考慮使用 CALayer 取代 UIView
- 不要頻繁調(diào)用 UIView 的相關屬性,例如 frame旁理、bounds樊零、transform 等屬性,盡量減少不必要的修改
- 盡量提前計算好布局孽文,在有需要時一次性調(diào)整對應的屬性驻襟,不要對此修改屬性
- Autolayout 會比直接設置 frame 消耗更多的 CPU 資源
- 圖片的 size 最好剛好更 UIImageView 的 size 保持一致
- 控制一下 線程的最大并發(fā)數(shù)量
- 盡量把耗時操作放到子線程
- 文本處理(尺寸計算、繪制)
- 圖片處理(解碼芋哭、繪制)
GPU 層面的優(yōu)化
- 盡量避免短時間內(nèi)大量圖片的顯示沉衣,盡可能你將多張圖片合成一張進行顯示
- GPU 能處理的最大紋理尺寸是
4096x4096
,一旦超過這個尺寸减牺,就會占用 CPU 資源進行處理厢蒜,所以紋理盡量不要超過這個尺寸 - 盡量減少視圖數(shù)據(jù)和層次
- 減少透明的視圖(alpha<1),不透明的就設置 opaque 為 YES(打開繪制優(yōu)化開關)
- 盡量避免出現(xiàn)離屏渲染
離屏渲染優(yōu)化
如何高性能的畫一個圓角烹植?
視圖和圓角的大小對幀率并沒有什么影響斑鸦,數(shù)量最核心的影響因素
這個是我們最常規(guī)的設置方式,但不可取草雕,因為會觸發(fā)離屏渲染
- 如果能夠只用 cornerRadius 解決問題巷屿,就不用優(yōu)化
- 如果必須設置 maskToBounds,可以參考圓角視圖的數(shù)量墩虹,如果數(shù)量少(一頁只有幾個)也可以考慮不用優(yōu)化嘱巾。
- UIImageView 的圓角通過直接截取圖片實現(xiàn),其他視圖的圓角可以通過 Core Graphics 畫出圓角矩陣實現(xiàn)
- 通過 CoreGraphic 畫一個圓角诫钓,不會觸發(fā)離屏渲染
什么是 “離屏渲染”旬昭?
離屏渲染就是在當前屏幕緩沖區(qū)外,新開辟一個緩沖區(qū)進行操作菌湃。
-
在 OpenGL 中问拘,GPU 有2中渲染方式
- On-Screen Rendering:當前屏幕渲染,在當前用于顯示的屏幕緩沖區(qū)進行渲染操作
- Off-Screen Rendering:離屏渲染惧所,在當前屏幕緩沖區(qū)以外開辟一個緩沖區(qū)進行渲染操作
為何要避免離屏渲染骤坐?
CPU、GPU 在繪制渲染視圖是做了大量的工作下愈。離屏渲染發(fā)生在 GPU 層面上纽绍,會創(chuàng)建新的渲染緩緩沖區(qū),會觸發(fā) OpenGL 的多通道渲染管線势似,圖像上下文切換會早晨額外的開銷拌夏,增加 GPU 工作量僧著。如果CPU、GPU累計耗時 16.67 ms還沒有完成障簿,就會造成卡頓掉幀霹抛。
圓角屬性、蒙層遮罩 都會觸發(fā)離屏渲染卷谈。指定以上屬性,標記了它在新的圖形上下文中霞篡,在未愈合之前世蔗,不可以用于顯示的時候就觸發(fā)了離屏渲染。
離屏渲染消耗性能的原因朗兵?
需要創(chuàng)建新的緩沖區(qū)
-
離屏渲染的整個過程污淋,需要多次切換上下文環(huán)境
- 上下文先從當前屏幕(On-Screen)切換到離屏(Off-Screen)
- 等離屏渲染結束后,將離屏緩沖區(qū)的結果顯示到屏幕上
- 再將上下文切換到當前屏幕
哪些操作會觸發(fā)離屏渲染余掖?
-
layer.shouldRasterzize:光柵化
- 光柵化概念:將圖轉化為一個個柵格組成的圖像
- 光柵化特點:每個元素對應幀緩沖區(qū)的一像素
- 光柵化限制:系統(tǒng)給光柵化限制了內(nèi)存寸爆,如果超過就會觸發(fā)離屏渲染,所以cell中一般不使用
mask:遮罩
shadows:layer.shadowXXX盐欺,如果設置了 layer.shadowPath 就不會產(chǎn)生離屏渲染
group opacity:不透明赁豆,layer屬性
edge antialiasing:抗鋸齒
cornerRadius:圓角。同時設置 layer.masksToBounds = YES; layer.cornerRadius 大于0冗美,考慮通過 CoreGraphics 繪制圓角魔种,或者讓美工提供圓角圖片
漸變
drawRect
離屏渲染 VS CPU 渲染
上面說到了,所有不在 GPU 的當前屏幕緩沖區(qū)進行的渲染都叫離屏渲染粉洼,還有另外一種特殊的離屏渲染节预,叫“CPU 渲染”。
-
CPU渲染:
- 如果重寫了 drawRect 方法属韧,并且使用任何 Core Graphics 的技術安拟,進行了繪制操作,就涉及到了 CPU渲染
- 整個渲染過程由 CPU 在 APP 內(nèi)同步完成宵喂,渲染得到的 bitmap 最后交給 GPU 用于顯示
由于 GPU 的浮點運算能力比 CPU 強糠赦,CPU 渲染的效率可能不如離屏渲染。但如果只是實現(xiàn)一個簡單的效果锅棕,直接使用CPU渲染就可以愉棱,因為離屏渲染涉及到緩沖區(qū)創(chuàng)建以及上下文切換等耗時操作。
如何檢測離屏渲染哲戚?
-
模擬器:
Debug->Color Off-screen Rendered
可以看到圖片
亮黃色
部分就是離屏渲染的視圖 -
真機:xcode9之后可以不用 Instrument 了奔滑,運行程序之后:
Debug -> View Debugging -> Rendering -> Color Offscreen-Rendered Yellow
離屏渲染的解決思路
-
預排班,提前計算
在接收到服務器端返回的數(shù)據(jù)后顺少,盡量將 CoreText 排版的結果朋其、單個空間的高度王浴、cell 整體的高度提前計算好,將其存儲在模型的屬性中梅猿。需要使用時氓辣,知己耳聰模型中往外取,避免了計算的過程袱蚓。
盡量少用 UILabel钞啸,可以使用 CALayer。避免使用 AutoLayout 的自動布局喇潘,才去純代碼的方式
-
預渲染体斩,提前繪制
圓形的圖標可以提前在:接收到網(wǎng)絡返回數(shù)據(jù)時,后臺線程進行處理颖低,直接存儲在模型數(shù)據(jù)中絮吵,回到主線程后直接調(diào)用
避免使用 CALayer 的 Border、Corner忱屑、Shadow蹬敲、Mask 等技術,這些都會觸發(fā)離屏渲染
異步繪制
全局并發(fā)線程
高效的圖片異步加載
圖層混合優(yōu)化
-
怎么檢測圖層混合
在下面 instrument 工具介紹中有給出
-
怎么避免圖層混合
- 確陛航洌控件的 Opaque 屬性設置為 true
- 確卑槲耍控件的 背景色 和父視圖的背景色一致 且不透明
- 如無特殊需要,不要設置低于 1 的 alpha 值
- 確保 UIImage 沒有alpha 通道
- UILabel iOS8以后設置背景色為非透明 和 設置 label.layer.masksToBounds=YES从铲,就可以讓label只渲染給定的size區(qū)域闹究,解決 UILabel 的圖層混合問題
instrument 工具
上面講到了如何檢測離屏渲染,除了離屏渲染 Rendering
還有其他幾種調(diào)試類型
-
Color Blended Layer :圖層混合
表示區(qū)域使用多種混合圖層食店,(圖層混合:由于多 UI/Layer 疊加渣淤,如果有透明或半透明顏色時,CPU就會去計算最終顯示的顏色吉嫩,中間就涉及很很多多余計算价认。
顏色標識
- 紅色:混合圖層 - 綠色:沒有使用混合
調(diào)優(yōu)
減少紅色區(qū)域 1. 設置 Opaque 屬性為 YES 2. 給 view 設置一個不透明的顏色
-
Color Hits green and Misses Red:光柵化(緩存layer)
檢測 layer 是否使用 shouldRasterize,為true開啟光柵化(默認)自娩,光柵化會將layer預先渲染為位圖 bitmap用踩,然后緩存,從而提高性能忙迁。
顏色標識
- 紅色:光柵化 - 綠色:未光柵化
調(diào)優(yōu)
使用內(nèi)容不變的layer脐彩,不適合tableview,會造成多余離屏渲染降低性能(原因:系統(tǒng)給光柵化限制了內(nèi)存姊扔,如果超過就會離屏渲染)
-
Color copied Images 圖片格式檢測與復制
Shows images that are copied by Core Animation in blue
惠奸,蘋果官方注釋說 被拷貝給CPU進行轉化的圖片顯示為綠色。如果 GPU 不支持當前圖片的顏色格式恰梢,那么就會將圖片交給 CPU 預先進行格式轉化佛南,并且這張圖片標記為綠色梗掰。
GPU 只解析 32 bit 的顏色格式,如果使用 Color Copied Images 調(diào)試嗅回,圖片是藍色
顏色標識
- 藍色:需要賦值
擴展
32bit 指圖片顏色深度及穗,用“位”來表示,用來表示顯示顏色數(shù)量绵载,例如一個圖片支持256種顏色埂陆,那么就需要256個不同的值來表示不同的顏色,就需要0-255娃豹,二進制表示就是從 00000000-11111111焚虱,一共需要 8位 二進制數(shù),所以**顏色深度是 8**培愁。通常32bit色彩中使用3個bit表示R(紅)G(綠)B(藍),還有一個 8bit 表示 Alpha(透明度)
-
Color misaliged Images:圖片尺寸匹配
目標像素與源像素不對齊的圖片缓窜,比如圖片大小和 UIImageView 大小不一致
顏色標識
- 洋紅色:圖片沒有像素對齊 - 黃色:圖片縮放
優(yōu)化
盡量匹配大小
-
Color Compositing Fast-Path Blue:快速路徑
標記由硬件繪制的路徑定续,顯示藍色,越多越好禾锤∷焦桑可以直接對OpenGL繪制的圖像高亮。
顏色標識
- 藍色
優(yōu)化
一般不做檢測
-
Flash updated Regions:重繪區(qū)域
對重繪區(qū)域高亮為黃色恩掷,會使用 CoreGraphic 繪制倡鲸,越小越好
顏色標識
- 黃色
-
Color Immediately:顏色刷新頻率
當執(zhí)行顏色刷新的時候移除 10ms 的延遲,因為可能在特定情況下你不需要這些延遲黄娘,所以使用此選項加快顏色刷新的頻率峭状。
一般用不到
opaque 繪制優(yōu)化
這個值不是決定視圖是否是透明的,而是給繪制系統(tǒng)提供一個個性能優(yōu)化的開關
- YES:不透明逼争。UIView 默認為 YES
- NO:透明优床。UIButton、UILabel等子類默認為 NO
red + green = yellow
在第一篇文章中介紹了一個公式:
R = S + D * (1 - Sa)
- R:像素RGB
- S:源色彩(頂端紋理)
- D:目標顏色(低一層的紋理)
- Sa:源色彩的透明度
- redView = (1, 0, 0, 1)
- greenView = (0, 1, 0, 0.5)
R = 1 + 0 * (1-0.5)
G = 0 + 1 * (1-0.5)
B = 0 + 0 * (1-0.5)
A = 1 + 0.5 * (1-0.5)
- 得出結果是:(1, 0.5, 0, 1)
而當 Sa=1 時誓焦,R=S胆敞,也就是說。這個時候不管目標顏色是什么杂伟,GPU 都不需要做任何計算合成移层。只需要簡單的從這個層進行拷貝,節(jié)省了GPU大量的工作量赫粥。