一、CPU 資源消耗原因和解決方案
1、對象創建,盡量使用輕量的對象代替重量的對象,例如用CALayer代替UIView
2、對象調整,盡量減少不必要的UI屬性修改
3、對象銷毀,可以異步放到后臺線程去銷毀
4、布局計算,盡量提前計算好布局,最好一次性調整好對應屬性
5、Autolayout,在復雜布局時盡量少使用Autolayout
6、文本計算,參考UILabel內部的計算方式,在后臺線程用[NSAttributedString boundingRectWithSize:options:context:] 來計算文本寬高,用 -[NSAttributedString drawWithRect:options:context:] 來繪制文本
7、文本渲染,可以自定義控件,用 TextKit 或最底層的 CoreText 對文本異步繪制
8、圖片的解碼,在后臺線程先把圖片繪制到 CGBitmapContext 中,然后從 Bitmap 直接創建圖片
9、圖像的繪制,圖像的繪制通常是指用那些以 CG 開頭的方法把圖像繪制到畫布中,然后從畫布創建圖片并顯示這樣一個過程,這個過程可以放到后臺線程進行
二、GPU 資源消耗原因和解決方案
GPU 處理的事情:接收提交的紋理(Texture)和頂點描述(三角形),應用變換(transform)、混合并渲染,然后輸出到屏幕上。
1、紋理的渲染
2、視圖的混合,view的opaque屬性設置成YES
3、圖形的生成,把需要顯示的圖形在后臺線程繪制為圖片,避免使用圓角、陰影、遮罩等屬性
1、預排版
從接口獲取數據轉成model之后,先在后頭線程算好各個控件應該顯示的frame及cell的高度,封裝成CellLayout對象。在tableview執行代理方法時直接取出數據布局,甚至可以把CellLayout對象緩存進內存中,這樣用戶滾動tableview時可以最大程度的提高性能。
2、預渲染
cell內容的離屏渲染會造成較大的GPU消耗,當要使用到Layer 的 border、corner、shadow、mask 等方法時,可以在后臺線程預渲染,然后單獨緩存到圖片緩存的隊列中去
- (UIImage *)imageWithCornerRadius:(CGFloat)radius {
CGRect rect = (CGRect){0.f, 0.f, self.size};
UIGraphicsBeginImageContextWithOptions(self.size, NO, UIScreen.mainScreen.scale);
CGContextAddPath(UIGraphicsGetCurrentContext(),
[UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:radius].CGPath);
CGContextClip(UIGraphicsGetCurrentContext());
[self drawInRect:rect];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
3、異步繪制
4、全局并發控制
3、更高效的異步圖片加載
UIImageView相對UIView來說會帶來額外的性能消耗,如果對性能有嚴格的要求,可以使用UIView.layer.contents來代替UIImageView,為此可以為CALayer加上setImageWithURL:方法。
4、進一步優化性能
減少view上圖層的數量,用CALayer代替UIView,
將cell按類型劃分,減少不必要的視圖對象和操作,
5、檢測性能的工具
FPS 指示器 YYFPSLabel 可以監測當前頁面的幀數。
MLeaksFinder 可以檢測內存泄露