標籤:eth 通過 內容 dispatch board pat 快捷 觀察 delegate
CPU資源消耗的原因和解決方案
對象建立
輕量對象代替重量對象
* 不需要響應觸摸事件的控制項:CALayer顯示
* 對象不涉及UI操作,則盡量放到後台線程建立
* 包含有CALayer的控制項只能在主線程建立和操作
* 通過Storyboard 建立視圖對象時,其資源消耗會比直接通過代碼建立對象要大非常多,在效能敏感的介面裡,storyboard不是一個好的技術選擇
* 盡量延遲對象建立的時間,並把對象的建立分散到多個任務中去。
* 對象的複用代價比釋放,建立新對象要小,這類對象應當盡量放到一個緩衝池裡複用
對象調整
* CALayer:CALayer內部並沒有屬性,當調用屬性方法時,它內部是通過運行時resolveInstanceMethod為對象臨時添加一個方法,並把對應屬性值儲存到內部的一個Dictionary裡,同時還會通知delegate,建立動畫等等,非常消耗資源。
* UIView的關於顯示相關的屬性(frame/bound/transform)等實際上都是CALayer屬性對應來的,所以對UIView的這些屬性進行調整時,消耗的資源要遠大於一般的屬性,所以,盡量減少不必要的屬性修改
* 當視圖層次調整時,UIView,CALayer之間會出現很多方法調用與通知,所以,應盡量避免調整視圖層次,添加和移除視圖。
對象銷毀
把對象捕獲到block中,然後扔到後台隊列去隨便發送個訊息以避免編譯器警告,就可以讓對象在後台線程銷毀了。
NSArray *tmp = self.array;self.array = nil;dispatch_async(queue,^{ [tmp class];});
布局計算
* 視圖布局的計算是App中最為常見的消耗CPU資源的地方
* 在後台線程提前計算好視圖布局,並且對視圖布局進行緩衝
* 用任何技術對視圖進行布局,最終都會落到對UIView.frame/bounds/center等屬性的調整上 對象調整:非常消耗資源,所以盡量提前計算好布局,在需要時一次性調整好對應屬性,而不要多次,頻繁的計算和調整這些屬性。
Autolayout
不手動調整frame 等屬性,可以用常見的快捷屬性:left/right/top/bottom/width/height,或使用ComponentKit,AsyncDisplayKit等架構
文本渲染
* 所有的常值內容控制項,在底層都是通過CoreText排版,繪製為Bitmap顯示的。
* 常見的文本控制項(UILabel,UITextView),其排版和繪製都是在主線程進行的,當顯示大量文本時,CPU的壓力會非常大。
* 解決方案:自訂文本控制項,用TextKit或底層的CoreText對文本非同步繪製
* CoreText對象建立好後,能直接擷取文本的寬高資訊,避免了多次計算(調整UILabel大小時算一遍,UILabel繪製時內部再算一遍),CoreText對象佔用記憶體較少,可以緩衝下來供稍後多次渲染。
圖片的解碼
* 用UIImage 或CGImageSource建立圖片時,圖片資料不會立刻解碼。圖片設定到UIImageView或者CALayer.contents中去,並且CALayer被提交到GPU前,CGImage中的資料才會得到解碼。 _發生在主線程,不可避免。_
* 後台線程先把圖片會知道CGBitmapContext中,然後從Bitmap直接建立圖片。
映像的繪製
* 映像繪製:以CG開頭的方法把映像繪製到畫布中,然後從畫布建立圖片並顯示 如:[UIView drawRect:]
* CoreGraphic 方法通常是安全執行緒的,映像的繪製可以放到後台線程進行
- (void)display{ dispatch_async(backgroundQueue,^{ CGContextRef ctx = CGBitmapContextCreate(...); // draw in context... CGImageRef img = CGBitmapContextCreateImage(ctx); CFRelease(ctx); dispatch_async(mainQueue,^{ layer.contents = img; });});}
GPU 資源消耗原因和解決方案
> GPU:接收提交的紋理和頂點描述(三角形),應用變換(transform),混合并渲染,然後輸出到螢幕上。
> 所看到的內容:紋理和形狀(三角形類比的向量圖形)
紋理的渲染
* 所有的Bitmap ,包括圖片,文本,柵格化的內容,最終都要由記憶體提交到顯存,綁定為GPU Texture.
* 提交到顯存的過程,GPU調整和渲染Texture的過程,都要消耗不少GPU資源
* 當在較短時間顯示大量圖片(TableView存在非常多的圖片並且快速滑動時),CPU佔有率很低,GPU佔有非常高,介面仍然會掉幀。
* 盡量減少在短時間內大量圖片的顯示,儘可能將多張圖片合成為一張進行顯示。
* 圖片過大,超過GPU的最大紋理尺寸時,圖片需要先由CPU進行預先處理,這對CPU和GPU都會帶來額外的資源消耗。iPhone4S以上機型,紋理尺寸上限4096*4096
視圖的混合
* 當多個視圖(CALayer)重疊在一起顯示時,GPU會首先把他們混合到一起。如果視圖結構過於複雜,混合的過程也會消耗很多GPU資源。
* 應用應當盡量減少視圖數量和層次,並在不透明的視圖裡標明opaque屬性以避免無用的Alpha通道合成。
* 把多個視圖預先渲染為一張圖片來顯示。
圖形的產生
* CALayer的border,圓角,陰影,遮罩(mask),CASharpLayer的向量圖形顯示,通常會觸發離屏渲染(offscreen rendering),而離屏渲染通暢發生在GPU中。
* 當一個列表視圖中出現大量圓角的CALayer,並且快速滑動時,可以觀察到GPU資源已經佔滿,而CPU資源消耗很少。介面仍然能正常滑動,但平均幀數會降到很低
* 避免這種情況,可以嘗試開啟CALayer.shouldRasterize(柵格化)屬性,但這會把原本離屏渲染的操作轉嫁到CPU上去。
* 圓角圖片遮擋
* 把需要顯示的圖形在後台線程繪製為圖片,避免使用圓角,陰影,遮罩等屬性。
iOS構建流暢的互動介面--CPU,GPU資源消耗的原因和解決方案