iOS UITableView性能優化 —— HERO博客

1. cell重用,註冊重用標識符

        tableView會根據屏幕可顯示的cell個數去創建cell,當cell劃出屏幕時會放到重用池,有cell需要顯示時,會根據標識符先去重用池取,有則拿出來顯示,沒有再去創建。

static NSString *identifier = @"cellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (!cell) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}
return cell;

2. 避免cell的重新佈局

        cell的佈局填充等操作比較耗時,一般創建時就佈局好,如可以將cell單獨放到一個自定義類,初始化時就佈局好。


3. 提前計算並緩存cell的屬性及內容

        tableView實現數據源方法後,編譯器會先調用tableView:heightForRowAtIndexPath:確定每一個cell的高度,在調用tableView:cellForRowAtIndexPath:創建要顯示的cell,滾動時,每當cell進入屏幕都會計算高度,編譯器知道高度後,會去創建cell,所以提前緩存cell高度可以避免重複的計算。如果cell是固定高度直接寫self.tableView.rowHeight = 70;不需要實現tableView:heightForRowAtIndexPath:方法以節省不必要的開銷。

        舉個例子來說:如果當前數據源有100條數據,當前屏幕最多隻能顯示5個。那麼刷新UITableView時,UITableView會先調用100次tableView:heightForRowAtIndexPath:方法,然後調用5次tableView:cellForRowAtIndexPath:方法;滾動屏幕時,每當Cell進入屏幕,都會調用一次tableView:heightForRowAtIndexPath:、tableView:cellForRowAtIndexPath:方法。

        所以儘量不要在tableView:heightForRowAtIndexPath:方法中調用tableView:cellForRowAtIndexPath:方法。

4. 減少cell中控件的數量       

         我們在cell上添加系統控件的時候,實際上系統都會調用底層的接口進行繪製,大量添加控件時,會消耗很大的資源並且也會影響渲染的性能。當使用默認的UITableViewCell並且在它的ContentView上面添加控件時會相當消耗性能。所以目前最佳的方法還是繼承UITableViewCell,並重寫drawRect方法。儘量使cell的佈局大致相同,不同風格的cell可以使用不同的重用標識符。


5. 儘量不要用透明屬性

        cell的opaque值設爲Yes,儘量不要使用控件透明屬性,cell自身也是,透明度也避免設置爲0,渲染耗時比較長。


6. 使用局部刷新

         如果只是更新某組、某行的話,使用局部刷新。


7. 網絡數據異步加載,不要阻塞主線程

         如果Cell內的內容來自web,需要加載網絡數據,下載圖片,配合SDWebImage、YYWebImage等實現異步加載、緩存。不要在主線程做一些文件的I/O操作。

8. 不要動態給cell添加或刪除控件

         儘量不要給cell動態添加刪除控件,初始化時添加控件,不適用的可以先隱藏。


9. 按需加載cell

         cell滾動很快時,只加載範圍內的cell,可以提高流暢度。


10. 不要實現無用的代理方法,tableView只遵守兩個協議


11. 圓角優化(點擊查看:iOS 控件設置圓角,避免離屏渲染

在APP開發中,圓角圖片還是經常出現的。如果一個界面中只有少量圓角圖片或許對性能沒有非常大的影響,但是當圓角圖片比較多的時候就會對性能產生明顯的影響,我們設置圓角一般通過如下方式:

view.layer.cornerRadius = 5.f;
view.layer.masksToBounds = YES;

這樣處理的渲染機制是GPU在當前屏幕緩衝區外新開闢一個渲染緩衝區進行工作,也就是離屏渲染,這會給我們帶來額外的性能損耗,如果這樣的圓角操作達到一定數量,會觸發緩衝區的頻繁合併和上下文的的頻繁切換,性能的代價會宏觀地表現在用戶體驗上——掉幀,點擊鏈接查看如何正確設置圓角注意一點,單獨設置view.layer.masksToBounds = YES;是不會發生離屏渲染的,上面說過儘量不要使用控件透明,如一個標籤UILable,儘量用如下方法:

label.backgroundColor = [UIColor whiteColor];
label.layer.masksToBounds = YES;

給定一個背景色,然後設置layer的masksToBounds屬性爲YES,因爲如果label的內容是中文,label實際渲染區域要大於label的size,最外層多了一個sublayer,如果不設置,label的邊緣外層顏色仍然需要計算,增加了GPU的性能消耗。 


12. 不要做多餘的繪製工作

         在實現drawRect:的時候,異步繪製,它的rect參數就是需要繪製的區域,這個區域之外的不需要進行繪製。繪製cell不建議使用UIView,建議使用CALayer,從形式來說,UIView的繪製是建立在CoreGraphic上的,使用的是CPU。CALayer使用的是Core Animation,CPU,GPU通吃,由系統決定使用哪個。View的繪製使用的是自下向上的一層一層的繪製,然後渲染。Layer處理的是Texure,利用GPU的Texture Cache和獨立的浮點數計算單元加速紋理的處理。從事件的響應來說,UIView是CALayer的代理,layer本身並不能響應事件,因爲layer是直接繼承自NSObject,不具備處理事件的能力。而UIView是繼承了UIResponder的,這也是事件轉發的角度上說明,view要比單純的layer複雜的多。在滑動的列表上,多層次的view再加上各種手勢的處理勢必導致幀數的下降。


13. 預渲染圖像

         當新的圖像出現時,仍然會有短暫的停頓現象。解決的辦法就是在bitmap context裏先將其畫一遍,導出成UIImage對象,然後再繪製到屏幕。

         cell內容經常變動,不要開啓光柵化,shouldRasterize,光柵化是將一個layer預先渲染成位圖(bitmap),再加入到緩存中,因爲tableViewCell的繪製非常頻繁,內容在不斷的變化,如果使用了光柵化,會造成大量的離屏渲染降低性能。


14. 使用正確的數據結構來存儲數據


15. 儘可能重用開銷比較大的對象

         如NSDateFormatter 和 NSCalendar等對象初始化非常慢,我們可以把它加入類的屬性當中,或者創建單例來使用。


16. 儘量減少計算的複雜度

         在高分屏儘量用ceil、floor或round取整。不要出現1.3,10.333這樣的小數。


17. 複雜界面建議純代碼

         xib、storyboard雖然方便,但仍然需要系統自動轉碼,並且對於一些自定義的繪製也有侷限性






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章