tableview的優(yōu)化一直是一個(gè)很考驗(yàn)基本功的活兒腋舌,之前做項(xiàng)目的適合被這個(gè)問題困擾了很久渣聚,通過性能工具、查閱文檔解決蔬蕊,整理思路和解決方案如下:
tableview優(yōu)化最主要:復(fù)用cell结澄,header,footer實(shí)例岸夯;使用約束布局cell子控件時(shí)不多次添加約束麻献;圖片不過大,盡量不使用透明視圖猜扮;避免阻塞主線程勉吻;計(jì)算高度方法不做大量邏輯處理。
cell是否使用了復(fù)用機(jī)制而不是每一次都創(chuàng)建新的cell旅赢。
如果每次都創(chuàng)建新的cell齿桃,在滑動(dòng)的時(shí)候會(huì)表現(xiàn)為:剛開始的時(shí)候很順暢,但是會(huì)越來越卡煮盼,內(nèi)存跟著一直升高短纵,停止滑動(dòng)的時(shí)候也不會(huì)降下來。使用緩存機(jī)制創(chuàng)建的cell僵控,開始滑動(dòng)的時(shí)候內(nèi)存會(huì)開始上升踩娘,等創(chuàng)建了一個(gè)屏幕再加半屏的cell之后,內(nèi)存趨于平穩(wěn)喉祭。
cell是否添加了大量的子控件,或者對layer做了過多的操作雷绢。
如果添加了大量的子控件泛烙,使用drawRect方法添加子控件,平衡GPU與CPU的負(fù)擔(dān)翘紊。同時(shí)還需要注意盡量使用不透明視圖和不重疊的漸變蔽氨,否則會(huì)加大GPU的負(fù)擔(dān),造成性能不佳。
高度計(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í)際高度绍妨。但是在使用過程中會(huì)出現(xiàn)cell突然變高變得低的情況润脸,不適用于高度變化太大的cell。
2.如果使用約束布局創(chuàng)建的cell子控件他去,子控件之間都建立了相互約束毙驯,最上面的子控件與cell頂部建立約束,最下面的子控件與cell底部建立了約束灾测,相當(dāng)于子控件把cell撐開了爆价。
這時(shí)在高度計(jì)算方法中,走一遍cell的loaddata方法后可以通過
func systemLayoutSizeFittingSize(targetSize:CGSize) ->CGSize
取得cell的size媳搪,進(jìn)而得到cell高度铭段。通過這個(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è)問題了精刷!我講講我實(shí)現(xiàn)的思路:首先先注冊cell,當(dāng)緩存池中沒有cell時(shí)系統(tǒng)會(huì)自動(dòng)創(chuàng)建拗胜,有的話會(huì)直接取緩存中的cell返回給你。
override funcviewDidLodad(){? ? ? tableView.registerClass(CardCell.self, forCellReuseIdentifier: ID)}
用lazy創(chuàng)建一個(gè)cell實(shí)例怒允,由于lazy 關(guān)鍵字埂软,cell的創(chuàng)建只會(huì)執(zhí)行一次lazy
varcell:CardCell = {//已經(jīng)注冊過cell,當(dāng)緩存池中沒有cell時(shí)系統(tǒng)會(huì)自動(dòng)創(chuàng)建纫事,有的話會(huì)直接取緩存中的cell返回let v =self.myTableView?.dequeueReusableCellWithIdentifier(self.ID)as! CardCellreturnv }()
通過懶加載的方式勘畔,只創(chuàng)建一次cell的實(shí)例,避免內(nèi)存浪費(fè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).heightreturn height}
之前查資料的時(shí)候還有用空間換取時(shí)間的方案:
1)在請求網(wǎng)絡(luò)數(shù)據(jù)成功后就計(jì)算好高度并通過字典或者數(shù)組保存高度值钾唬,在高度方法中直接根據(jù)數(shù)組下標(biāo)或者key值取得高度并返回万哪。
2)還有建立一個(gè)frameModel的方法侠驯,與1中相似,只是獲得網(wǎng)絡(luò)數(shù)據(jù)后保存到frameModel中奕巍,在frameModel中定義一個(gè)類方法吟策,通過獲得的model值計(jì)算高度后返回。
避免快速滑動(dòng)情況下開過多線程的止。
cell中的圖片開線程異步加載檩坚,相信每個(gè)人都會(huì)想到。線程開過多了會(huì)造成資源浪費(fèi)冲杀,內(nèi)存開銷過大效床。圖片過多時(shí)可以不要一滾動(dòng)就走cellForRow方法,可以在scrollview的代理方法中做限制权谁,當(dāng)滾動(dòng)開始減速的時(shí)候才加載顯示在當(dāng)前屏幕上的cell(通過tableview的dragging和declearating兩個(gè)狀態(tài)也能判斷)
func tableView(tableView:UITableView, cellForRowAtIndexPath indexPath:NSIndexPath) ->UITableViewCell{? ? ? var canLoad:Bool = !tableView.dragging && !tableView.decelearatingifcanLoad {//開始loaddata剩檀,異步加載圖片 }}
圖片處理
1)后臺(tái)下載圖片后再回主線程刷新UI,避免阻塞主線程旺芽。
2)圖片過大回造成GPU負(fù)擔(dān)過大沪猴,可以在圖片下載后壓縮尺寸后顯示
3)避免對layer做過多的操作,盡量設(shè)置圖片為不透明
補(bǔ)充:
簡單的設(shè)置cornerRadius是不會(huì)影響性能的采章,但是設(shè)置了maskToBounds运嗜,會(huì)導(dǎo)致離屏渲染,應(yīng)減少設(shè)置圖層 maskToBounds = YES 悯舟,担租;
使用懶加載圖片的方式避免重復(fù)下載圖片,浪費(fèi)資源抵怎。圖片下載后并做壓縮處理后將其保存到緩存中奋救,下次加載此圖片之前先從緩存中取,如果取不到該圖片就在后臺(tái)下載保存反惕。
使用Core Graphics實(shí)現(xiàn)圓角等功能尝艘。
重寫drawRect方法會(huì)離屏渲染,導(dǎo)致內(nèi)存急劇上升姿染,即使在這個(gè)方法里面不寫一句代碼背亥,也會(huì)讓內(nèi)存升高。
鏈接:http://www.reibang.com/p/76cb55c6329f