tableView性能優(yōu)化

tableview的優(yōu)化一直是一個(gè)很考驗(yàn)基本功的活兒,之前做項(xiàng)目的適合被這個(gè)問(wèn)題困擾了很久,通過(guò)性能工具、查閱文檔解決,整理思路和解決方案如下:

tableview優(yōu)化最主要:復(fù)用cell,header,footer實(shí)例;使用約束布局cell子控件時(shí)不多次添加約束;圖片不過(guò)大,盡量不使用透明視圖;避免阻塞主線程;計(jì)算高度方法不做大量邏輯處理。
  • cell是否使用了復(fù)用機(jī)制而不是每一次都創(chuàng)建新的cell。

如果每次都創(chuàng)建新的cell,在滑動(dòng)的時(shí)候會(huì)表現(xiàn)為:剛開(kāi)始的時(shí)候很順暢,但是會(huì)越來(lái)越卡,內(nèi)存跟著一直升高,停止滑動(dòng)的時(shí)候也不會(huì)降下來(lái)。使用緩存機(jī)制創(chuàng)建的cell,開(kāi)始滑動(dòng)的時(shí)候內(nèi)存會(huì)開(kāi)始上升,等創(chuàng)建了一個(gè)屏幕再加半屏的cell之后,內(nèi)存趨于平穩(wěn)。

  • cell是否添加了大量的子控件,或者對(duì)layer做了過(guò)多的操作。

如果添加了大量的子控件,使用drawRect方法添加子控件,平衡GPU與CPU的負(fù)擔(dān)。同時(shí)還需要注意盡量使用不透明視圖和不重疊的漸變,否則會(huì)加大GPU的負(fù)擔(dān),造成性能不佳。

補(bǔ)充:請(qǐng)謹(jǐn)慎使用drawRect:方法,當(dāng)cell中只有少量的子視圖時(shí),應(yīng)當(dāng)避免使用,因?yàn)橹貙?xiě)drawRect:就是在此方法中一句代碼都不寫(xiě)也會(huì)占用5-6M的內(nèi)存。
  • 高度計(jì)算方法時(shí)不做復(fù)雜的計(jì)算,盡量只使用加減乘除。

自適應(yīng)高度的cell實(shí)現(xiàn)方式有很多種,比如,
1.使用iOS7以上系統(tǒng)的

func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat

這個(gè)方法中,可以先給一個(gè)估計(jì)的高度,系統(tǒng)會(huì)從你給定的高度再去計(jì)算實(shí)際高度。但是在使用過(guò)程中會(huì)出現(xiàn)cell突然變高變得低的情況,不適用于高度變化太大的cell。
2.如果使用約束布局創(chuàng)建的cell子控件,子控件之間都建立了相互約束,最上面的子控件與cell頂部建立約束,最下面的子控件與cell底部建立了約束,相當(dāng)于子控件把cell撐開(kāi)了。


約束簡(jiǎn)圖

這時(shí)在高度計(jì)算方法中,走一遍cell的loaddata方法后可以通過(guò)

func systemLayoutSizeFittingSize(targetSize: CGSize) -> CGSize 

取得cell的size,進(jìn)而得到cell高度。
通過(guò)這個(gè)方法獲取的cell高度是十分精確的,只要?jiǎng)?chuàng)建好子控件的約束就能獲得cell的size。比較不好的是只是這種方法會(huì)重走一遍cell的loaddata方法。除此之外在調(diào)用cell的loaddata之前需要得到cell的實(shí)例,實(shí)例創(chuàng)建的方式應(yīng)該與cellForRow方法一樣,優(yōu)先從緩存池中取得。
這個(gè)方案可能會(huì)創(chuàng)建多個(gè)cell。如果能在內(nèi)存匯總保存一份cell的實(shí)例就能解決這個(gè)問(wèn)題了!我講講我實(shí)現(xiàn)的思路:
首先先注冊(cè)cell,當(dāng)緩存池中沒(méi)有cell時(shí)系統(tǒng)會(huì)自動(dòng)創(chuàng)建,有的話會(huì)直接取緩存中的cell返回給你。

override func viewDidLodad() {
      tableView.registerClass(CardCell.self, forCellReuseIdentifier: ID)
}

用lazy創(chuàng)建一個(gè)cell實(shí)例,由于lazy 關(guān)鍵字,cell的創(chuàng)建只會(huì)執(zhí)行一次

lazy var cell:CardCell = {
        //已經(jīng)注冊(cè)過(guò)cell,當(dāng)緩存池中沒(méi)有cell時(shí)系統(tǒng)會(huì)自動(dòng)創(chuàng)建,有的話會(huì)直接取緩存中的cell返回
        let v = self.myTableView?.dequeueReusableCellWithIdentifier(self.ID) as! CardCell
        return v
        }()

通過(guò)懶加載的方式,只創(chuàng)建一次cell的實(shí)例,避免內(nèi)存浪費(fèi)。
接下來(lái)要做的步驟就是之前講的,調(diào)用cell的loadData方法,計(jì)算高度

func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    self.imageCell.loadData(d)    
    let height:CGFloat = self.cell.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
return height
}

之前查資料的時(shí)候還有用空間換取時(shí)間的方案:
1)在請(qǐng)求網(wǎng)絡(luò)數(shù)據(jù)成功后就計(jì)算好高度并通過(guò)字典或者數(shù)組保存高度值,在高度方法中直接根據(jù)數(shù)組下標(biāo)或者key值取得高度并返回。
2)還有建立一個(gè)frameModel的方法,與1中相似,只是獲得網(wǎng)絡(luò)數(shù)據(jù)后保存到frameModel中,在frameModel中定義一個(gè)類方法,通過(guò)獲得的model值計(jì)算高度后返回。

  • 避免快速滑動(dòng)情況下開(kāi)過(guò)多線程。

cell中的圖片開(kāi)線程異步加載,相信每個(gè)人都會(huì)想到。線程開(kāi)過(guò)多了會(huì)造成資源浪費(fèi),內(nèi)存開(kāi)銷過(guò)大。圖片過(guò)多時(shí)可以不要一滾動(dòng)就走cellForRow方法,可以在scrollview的代理方法中做限制,當(dāng)滾動(dòng)開(kāi)始減速的時(shí)候才加載顯示在當(dāng)前屏幕上的cell(通過(guò)tableview的dragging和declearating兩個(gè)狀態(tài)也能判斷)

  func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        var canLoad:Bool = !tableView.dragging && !tableView.declearating
        if  canLoad {
            //開(kāi)始loaddata,異步加載圖片
      }
}
  • 圖片處理

1)后臺(tái)下載圖片后再回主線程刷新UI,避免阻塞主線程。
2)圖片過(guò)大回造成GPU負(fù)擔(dān)過(guò)大,可以在圖片下載后壓縮尺寸后顯示
3)避免對(duì)layer做過(guò)多的操作,盡量設(shè)置圖片為不透明

補(bǔ)充:
  • 簡(jiǎn)單的設(shè)置cornerRadius是不會(huì)影響性能的,但是設(shè)置了maskToBounds,會(huì)導(dǎo)致離屏渲染,應(yīng)減少設(shè)置圖層 maskToBounds = YES ,;
  • 使用懶加載圖片的方式避免重復(fù)下載圖片,浪費(fèi)資源。圖片下載后并做壓縮處理后將其保存到緩存中,下次加載此圖片之前先從緩存中取,如果取不到該圖片就在后臺(tái)下載保存。
  • 使用Core Graphics實(shí)現(xiàn)圓角等功能。
  • 重寫(xiě)drawRect方法會(huì)離屏渲染,導(dǎo)致內(nèi)存急劇上升,即使在這個(gè)方法里面不寫(xiě)一句代碼,也會(huì)讓內(nèi)存升高。

參考:
iOS 高效添加圓角效果實(shí)戰(zhàn)講解
消息別讓圓角成為你的列表殺幀高手
內(nèi)存惡鬼DrawRect
關(guān)于性能的一些問(wèn)題

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • tableview的優(yōu)化一直是一個(gè)很考驗(yàn)基本功的活兒,之前做項(xiàng)目的適合被這個(gè)問(wèn)題困擾了很久,通過(guò)性能工具、查閱文檔...
    青蔥烈馬閱讀 4,535評(píng)論 1 7
  • 一、tableview通用工作流程 一個(gè)tableView需要顯示內(nèi)容的時(shí)候,首先會(huì)發(fā)送網(wǎng)絡(luò)請(qǐng)求,向服務(wù)器請(qǐng)求數(shù)據(jù)...
    強(qiáng)降雨天氣閱讀 906評(píng)論 0 5
  • TableView相信只要是做iOS開(kāi)發(fā)的就不會(huì)陌生,目前大多數(shù)iOS的app都是采用TabBar+Navigat...
    90后的思維閱讀 752評(píng)論 0 6
  • 生活不會(huì)永遠(yuǎn)按照我們的意愿進(jìn)行。 孩子也不可能按照我們的意愿來(lái)活。遇到問(wèn)題,在所難免。 正面管教這一章強(qiáng)調(diào)關(guān)注于解...
    葉子暖洋洋閱讀 371評(píng)論 0 0
  • 我不懂夸父為何一直逐日 可能我習(xí)慣了日出日落 我不懂精衛(wèi)為何一直填海 可能我習(xí)慣了四季變換 我不懂 直到遇見(jiàn)了你 ...
    哆啦A念閱讀 205評(píng)論 0 0

友情鏈接更多精彩內(nèi)容