影響性能的原因有很多種,以下列舉最主要的幾點(diǎn): 1、 cellForRowAtIndexPath方法中處理了過多的業(yè)務(wù)。 2、 tableViewCell的SubView層級太復(fù)雜,做了大量的透明處理。 3、 cell的height動態(tài)變化時計算方法不對。
關(guān)于影響性能的前兩點(diǎn)比較好理解,此文檔主要針對第三種情況做以處理。想要對tableView做性能優(yōu)化,只能從tableView的數(shù)據(jù)源方法入手,而tableView的代理方法中,主要有兩個方法為我們所用:cellForRow和heightForRow。下面我們針對這兩個方法進(jìn)行深入分析,并給出解決方案。
tableView:heightForRowAtIndexPath
TableView在每次reload data 時都需要所有cell的高度。也就是說如果有100行cell,那么每調(diào)用一次reload data ,就會調(diào)用100次heightForRowAtIndexPath方法獲取每個cell的高度,而不是說只獲取當(dāng)前屏幕顯示的cell的高度。對于高度的計算,這里有個小細(xì)節(jié)需要注意,如果所有cell的高度都固定,那么就刪除代理中的這個tableView:heightForRowAtIndexPath:方法。設(shè)置tableView的rowHeight屬性。蘋果的文檔里也介紹了這樣可以減少調(diào)用時間。那么對于類似微博、微信朋友圈使用動態(tài)的高度,不定數(shù)量的文字,可能會有圖片,數(shù)量和大小也不固定的情況下,傳統(tǒng)的方法是為cell寫個計算行高的類方法,傳入那些動態(tài)的元素(文字,圖片等),然后返回計算后的高度。在tableView:heightForRowAtIndexPath:中調(diào)用這個方法,填入需要的參數(shù)來計算cell高度。當(dāng)然這沒有什么問題,而且我們程序里也是這么做的。但是如果計算量很復(fù)雜,每次reload Data,光計算行高就花去了rowCount * 單行高的計算時間。假如有100行或更多時,程序里可能不定期的需要reload data 或者insertRow亦或者deleteRow,那么調(diào)用時間和內(nèi)存消耗都很大。解決辦法:用“空間換時間”
用“空間換時間”簡單說就是將計算行高的時間提前到從服務(wù)器返回數(shù)據(jù)的時候,計算完了行高一并寫入數(shù)據(jù)庫中。2. tableView:cellForRowAtIndexPath:
在cellforRow回調(diào)的優(yōu)化上,思路同上,也是通過預(yù)處理減少在這個回調(diào)中的計算時間。不過,主要針對圖片的異步加載進(jìn)行優(yōu)化。 圖片的異步加載無非就是在這個方法里發(fā)起異步請求,圖片加載完后根據(jù)UIImageView的引用設(shè)置圖片。在這里,使用懶加載的方式減少快速滑動時因為網(wǎng)絡(luò)請求過于頻繁與切換線程顯示圖片造成卡頓。還有個細(xì)節(jié),從服務(wù)器拿回來的圖片和最后顯示的大小可能不一樣。這就涉及到對圖片的壓縮。在顯示時,控件加了約束,圖片可能會適應(yīng)控件大小,圖片變形需要對圖片做transform。每次壓縮圖片都要對圖片乘以一個變換矩陣,如果圖片很多,這個計算量是不容忽視的。優(yōu)化建議:
從網(wǎng)絡(luò)拿回圖片后,先根據(jù)需要顯示的圖片大小切成適合大小的圖,每次只顯示處理過大小的圖片。當(dāng)查看大圖時再顯示大圖,如果服務(wù)器能直接返回預(yù)處理好的小圖和圖片的大小更好。Ps:我們公司的程序里,文件服務(wù)器會有多種格式的圖片大小,每次請求時會附帶大小規(guī)格,但是,目前文件服務(wù)器支持的小圖規(guī)格和UI上的控件大小還是不一致,還是會進(jìn)行壓縮。
// 等比縮放
- (UIImage *)hyb_cropEqualScaleImageToSize:(CGSize)size { CGFloat scale = [UIScreen mainScreen].scale; // 這一行至關(guān)重要 // 不要直接使用UIGraphicsBeginImageContext(size);方法 // 因為控件的frame與像素是有倍數(shù)關(guān)系的 // 比如@1x、@2x、@3x圖,因此我們必須要指定scale,否則黃色去不了 // 因為在5以上,scale為2,6plus scale為3,所生成的圖是要合蘋果的 // 規(guī)格才能正常 UIGraphicsBeginImageContextWithOptions(size, NO, scale); CGSize aspectFitSize = CGSizeZero; if (self.size.width != 0 && self.size.height != 0) { CGFloat rateWidth = size.width / self.size.width; CGFloat rateHeight = size.height / self.size.height; CGFloat rate = MIN(rateHeight, rateWidth); aspectFitSize = CGSizeMake(self.size.width * rate, self.size.height * rate); } [self drawInRect:CGRectMake(0, 0, aspectFitSize.width, aspectFitSize.height)]; UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return image;}直接縮放至指定大小// 非等比縮放,生成的圖片可能會被拉伸
- (UIImage *)hyb_cropEqualScaleImageToSize:(CGSize)size { CGFloat scale = [UIScreen mainScreen].scale; UIGraphicsBeginImageContextWithOptions(size, NO, scale); [self drawInRect:CGRectMake(0, 0, size.width, size.height)]; UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return image; }聲明:本文部分內(nèi)容參考于編程小翁和標(biāo)哥博客。
新聞熱點(diǎn)
疑難解答