1. 程式人生 > >【iOS】tableView的優化

【iOS】tableView的優化

在IOS開發中,UITableView是最重要,最常用的控制元件之一。而對於UITableView的優化,也是IOS開發程式設計師必須要思考的問題。剛好前段時間,做的一個專案就碰到有關UITableView優化,自己也找了很多資料,所以在這裡整理一下我對tableView優化的理解。

1.cell的重用

UITableView中最重要的就是cell的重用機制,只要是用了UITableView控制元件,就必定會涉及cell的重用。cell的重用機制:當tableView顯示的時候,只會建立在可視範圍的cell,為了使這些cell可以重用,cell在建立的時候會有一個重用標識 ReuseIdentifier。當螢幕滾動時,有部分cell就會被移出螢幕,這些cell會被放到一個快取池中,等待重用。當需要顯示一個cell的時候,首先會到快取池中檢視有沒有對應的可重用的cell,如果有,就直接拿來用,如果沒有,再去建立,這樣就會大大減少記憶體的消耗。

 

    override func viewDidLoad() {
        super.viewDidLoad()
        
        tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: ReuseIdentifier)
        
    }

 

 

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier(ReuseIdentifier, forIndexPath: indexPath)
        return cell
    }

 

 

 

 

 

2.快取行高

在呈現cell之前,把cell的高度計算好快取起來,避免每次載入cell的時候都要計算。對於高度的計算,還有個小細節需要注意,就是如果 row 的高度都一定,那就刪除代理中的這個 tableView:heightForRowAtIndexPath: 方法,設定 Table View 的 rowHeight 屬性。

 

 

    override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        //獲得模型
        let model = models![indexPath.row]
        
        //判斷模型裡面之前有沒有快取過行高
        if model.rowHeight != nil {
            return model.rowHeight!
        }
        
        //自己算行高:AutoLayout
        //讓 cell自己對應內容,直接獲取高度,這個cell不參與顯示
        let cell = tableView.dequeueReusableCellWithIdentifier(ReuseIdentifier) as! CJStatusCell
        cell.model = model
        
        let heigth = cell.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
        
        //儲存行高
        model.rowHeight = heigth
        return heigth
    }

 

 

 

3.cellForRowAtIndexPath不要做耗時操作

主執行緒主要是用來顯示UI,重新整理介面的,為了不影響介面的流暢程度,耗時的操作都放到子執行緒去執行。

4.儘量不要去新增和移除view, 先將會用到的控制元件懶載入,要就顯示,不要就隱藏。如果cell中有圖片控制元件,就使用非同步載入圖片。

5.減少cell上subviews的數量

UITableViewCell包含了textLabel、detailTextLabel和imageView等,而你還可以自定義一些檢視放在它的contentView裡。然而view是很大的物件,建立它會消耗較多資源,並且也影響渲染的效能。

6.cell裡面的控制元件,約束最好不要使用remake,動態新增約束是比較耗效能的

7.cell裡面的控制元件,背景最好是不透明的 (圖層混合), view的背景顏色 clearColor儘量少

8.圖片圓角不要使用 layer.cornerRadius,圖層最好不要使用陰影, 陰影會導致離屏渲染

9.非同步繪製

我在這邊寫了一個UIImage的分類,是用來非同步繪製。

 

import UIKit

extension UIImage {
    func cj_AsyncDrawImage(var size: CGSize?, bgColor: UIColor? = UIColor.whiteColor(), isCorner: Bool = false, drawFinish: (image: UIImage)->()) {
        
        let start = CACurrentMediaTime()
        
        if size == nil {
            //別人沒有傳入size
            size = self.size
        }
        //上下文大小為rect
        let rect = CGRect(origin: CGPointZero, size: size!)
        
        //開啟上下文
        UIGraphicsBeginImageContextWithOptions(size!, bgColor != nil, UIScreen.mainScreen().scale)
        
        //設定背景顏色
        bgColor?.setFill()
        UIRectFill(rect)
        
        //需要圓角
        if isCorner {
            //路徑
            let path = UIBezierPath(ovalInRect: rect)
            //讓後面繪製的元素在路徑裡面
            path.addClip()
        }
        
        self.drawInRect(rect)
        
        //獲取圖片
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        //結束上下文
        UIGraphicsEndImageContext()
        
        let end = CACurrentMediaTime()
        
//        CJPrint("非同步繪製時間:\(end - start)")
        
        //返回繪製好的圖片
        dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in
            drawFinish(image: newImage)
        }
    }
}