CPU 負責計算顯示內容,比如視圖的創建、布局計算、圖片解碼、文本繪制等。隨后 CPU 會將計算好的內容提交到 GPU 去,由 GPU 進行變換、合成、渲染。CPU和GPU任一阻礙流程,都會造成掉幀現象,從而卡頓。所以優化主要集中在減少CPU的計算和GPU的渲染。
UIView 持有 CALayer 用于顯示,View 中大部分顯示屬性實際是從 Layer 映射而來;Layer 的 delegate 在這里是 View,當其屬性改變、動畫產生時,View 能夠得到通知。UIView 和 CALayer 不是線程安全的,并且只能在主線程創建、訪問和銷毀。對于不需要響應觸摸事件的控件,用CALayer會更加輕量。
避免對UIView使用透明。(UIView默認是非透明)。原因是透明對性能要求較高,如果在滾動時頁面比較復雜,體驗上的差異會相對明顯。UIView的背景色避免使用clearColor
減少視圖或者layer的層級數量,在有多個層級時,可以將多圖合并成一張圖,再渲染顯示。
避免圖像融合,不透明的視圖顯示設置opaque屬性為YES,避免alpha通道合成;
避免離屏渲染,CALayer的 border、圓角、陰影、遮罩mask,CASharpLayer的矢量圖形顯示,通常會觸發離屏渲染(offscreen rendering),而離屏渲染通常發生在 GPU 中。
將繪制圖像放在子線程中執行,如在子線程中使用 CGContext進行畫圖,在主線程中 layer.contents = img。(針對顯示單張圖片,不需進行交互的時候)
當GPU 資源已經占滿,而 CPU 資源消耗很少時,可適當使用Rasterize(光柵欄),但這會把原本離屏渲染的操作轉嫁到 CPU 上去。比如出現大量圓角的 CALayer,并且快速滑動時,最徹底的解決辦法,就是把需要顯示的圖形在后臺線程繪制為圖片,避免使用圓角、陰影、遮罩等屬性。
避免過于龐大的xib。隨著視圖數量的增長,Autolayout 帶來的 CPU 消耗會呈指數級上升
使圖片符合UIImageView的尺寸。不要在運行的時候再讓UIImageView自行壓縮,因為這樣會降低運行時的性能。(注:手動壓縮圖片的方法,在context中使用drawInRect)
設置UIView的背景圖片時,如果是整幅圖,就采用addSubView一個UIImageView;如果是要重復平鋪一個小圖,就使用colorWithPatternImage,因為這個函數的設計上就是針對小圖的,如果用于整幅大圖來做背景,反而會消耗更多內存。
對于重復使用的圖片使用imageNamed:來創建(這個會緩存),對于不需重復使用的,使用imageWithContentsOfFile。
UITableView的高度有時候會根據內容來自動計算,這種情況比較消耗資源。如果明知有哪幾種高度的話,就將高度緩存重用;盡量不要在 cellForRowAtIndexPath:方法中做很多事情。不僅僅重用cell,對于section的header和footer也進行重用。推薦優化UITableViewCell高度計算的那些事
選擇合適的collection。 如:Array使用下標查找較快,但插入和刪除較慢。set進行插入和刪除很快。
對常用的東西進行緩存。如從網上下載的需要經常顯示的圖片(這個在許多第三方框架如SDWebImage中都已經使用了)。對于一些下載下來,明顯不需要訪問網絡再獲取的圖片,可以直接為其制造一個NSURLRequest,并使這個NSURLRequest僅從緩存讀取數據。對于另外一些不涉及HTTP請求地址的數據,可以通過NSCache進行緩存。
重用一些高消耗的對象,如NSDateFormatter、NSCalender等。解決方法:可以將其作為property、甚至是靜態變量作為單例在APP中使用。并且,NSDateFormatter的 setDateFormate也是非常消耗資源的一個操作。
對于排版復雜的文字或者圖文混排,使用CoreText技術。(而不是一味地堆UILabel)
在對渲染的效率要求較高的頁面中,避免使用UILabel、UITextView等在主線程中進行排版和繪制的控件。應自定義文本控件,用TextKit或者CoreText進行文本異步繪制。另外,還有facebook的AsyncDisplayKit框架可以采用。