之前曾寫過一篇如何通過分類設置純色圖片\帶圓角圖片等的文章,連接:
http://www.lxweimin.com/writer#/notebooks/5359278
上述方法比較簡單粗暴,除了在設置圓角圖片時避免了離屏渲染的問題,其他性能上并未做優化處理,接下來,繼續整理一下對設置圖片性能提升方面的處理,這里我們將會借助模擬器為我們提供的兩種模式來對項目進行優化:Color Misaligned Images和 Color Blended Layers .
Tableview是日常開發中十分常見的控件,仔細觀察會發現,為什么有的app在滾動時,界面非常流暢,而有的app則顯得卡頓呢?
先來分析下,在Tableview中往往只有兩部分的操作:
1.獲取重用Cell
2.根據模型設置數據
通過緩存池和Cell的重用機制,很大程度上緩解了CPU的開銷和內存的浪費
而我們需要考慮的就是在獲取到重用Cell后,在給Cell設置數據時,減少其對控件的處理來提升性能
Cell中最常見的控件無非就是UIImageView和UILabel,而我們又能夠做哪些優化以及系統在設置數據環節還額外的做了哪些處理呢?
首先一點,我們在使用圖片時,往往一些圖片和視圖上的UIImageView尺寸不符,這就導致了圖片在設置時,系統要為其做拉伸/縮放處理,如果一個Tableview中需要系統做拉伸/縮放處理的UIImageView很多,就會在一定程度上的出現卡頓的現象
前面都是鋪墊,接下來才是這篇文章的重點:如何高性能的設置圖片
首先,借助模擬器,我們可以判斷出,哪些控件的尺寸是系統做過處理的
模擬器菜單欄中-->Debug-->Color Misaligned Images
如果勾選后,圖像顯示為黃色,代表當前圖片的大小和使用的ImageView大小不一致,做過拉伸處理
代碼演示:
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
imageView.center = self.view.center;
[self.view addSubview:imageView];
// 直接按照ImageView的尺寸來設置圖片
// 圖片的真實尺寸: 640 × 480 pixels
imageView.image = [UIImage imageNamed:@"路飛.jpg"];
效果圖:
開啟 Color效果圖:
補充說明:使用模擬器判斷縮放時,需要注意模擬器自身的尺寸是否進行過縮放(cmd+1 - 100%...),這里考慮到顯示器尺寸,為了讓100%顯示的模擬器完全顯示在屏幕上(如果是5.5寸,100%顯示屏幕上顯示不全),考慮到呈現效果,使用了6s模擬器
解決方式:
按照UIImageView的尺寸,提前對圖片進行拉伸/縮放處理,設置一致后再將圖片設置給UIImageView
- (UIImage *)js_imageWithSize:(CGSize)size{
// 開啟圖形上下文
UIGraphicsBeginImageContextWithOptions(size, YES, 0.0);
// 設置rect
CGRect rect = CGRectMake(0, 0, size.width, size.height);
// 將圖片繪制到圖形上下文
[self drawInRect:rect];
// 從圖形上下問獲取圖片
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
// 關閉圖形上下文
UIGraphicsEndImageContext();
// 返回圖片
return image;
}
效果圖:
這樣便解決了圖片與UIImageView尺寸不一致,系統對齊進行拉伸操作而帶來的性能上的浪費
尺寸不一致的問題我們處理完了,設置圓角也是同理
其次,使用顏色的時候,盡可能不要使用帶透明度的顏色(不要設置Alpha值)
假設在視圖控制器的View中放置一個BlueView和一個GreenView
因視圖上產生疊加,默認不設置透明度,處于上層的BlueView就會將疊加部分的GreenView遮擋;
而這時我將處于上層的BlueView設置了透明度,這樣GreenView與BlueView疊加部分就會被透出來
在整個屏幕繪制過程中:
1.先將BlueView沒有被疊加部分繪制出來
2.其次計算BlueView和BlueView疊加部分區域大小
3.然后再根據BlueView顏色的透明度,疊加了GreenView顏色計算產生的顏色,使用計算的顏色值繪制疊加部分
4.繪制BlueView疊加部分外的區域
從分析結果來看,如果使用了透明度顏色也會嚴重影響性能,所以在開發中如果不是剛需,盡量避免使用透明度顏色
既然分析出了需要優化改進的點,那么我們繼續使用模擬器自帶的功能來對項目進行改進
模擬器菜單欄中-->Debug-->Color Blended Layers
勾選"Color Blended Layers"
這是模擬器為我們提供的一種混合模式
通過混合模式我可以判斷出哪些部分進行過透明處理
如果控件部分顯示了紅色,則表明進行過透明處理,可以對其進行性能上的優化
這里先直接使用上篇文章中設置圓角圖片的類方法來演示下效果:
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
imageView.center = self.view.center;
[self.view addSubview:imageView];
// 方式一: 設置圓角圖片
UIImage *image = [UIImage imageNamed:@"路飛.jpg"];
imageView.image = [UIImage js_imageWithOriginalImage:[image js_imageWithSize:CGSizeMake(200, 200)]];
注意:在UIKit中UILabel的性能是比較差的,但又是不得不用的(也可以自己寫一個或者使用其他的開源框架),除了UILabel外,其他的出現混合模式的視圖,能處理的我們都應該盡可能的進行優化
代碼優化:
// 生成圓角圖片(優化后)
- (UIImage *)js_cornerImageWithSize:(CGSize)size{
// 開啟圖形上下文
UIGraphicsBeginImageContextWithOptions(size, YES, 0.0);
// 設置rect
CGRect rect = CGRectMake(0, 0, size.width, size.height);
// 計算半徑
CGFloat cornerRadius = MIN(size.width, size.height) * 0.5;
// 設置圓形路徑并切割
[[UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:cornerRadius] addClip];
// 將原始圖片繪制到圖形上下文中
[self drawInRect:rect];
// 從圖形上下獲取圖片
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
// 關閉圖形上下文
UIGraphicsEndImageContext();
// 返回圓形圖片
return image;
}
效果圖:
不再顯示紅色
由于開啟圖形上下文時參數設置為YES(不透明),所以顯示有黑邊,為了高性能的回去圓形圖片,避免設置透明色,我們來傳遞一個填充色來解決黑邊的問題
// 生成圓角圖片(優化后)
- (UIImage *)js_cornerImageWithSize:(CGSize)size fillClolor:(UIColor *)fillColor{
// 開啟圖形上下文
UIGraphicsBeginImageContextWithOptions(size, YES, 0.0);
// 設置rect
CGRect rect = CGRectMake(0, 0, size.width, size.height);
// 設置填充色
[fillColor set];
UIRectFill(rect);
// 計算半徑
CGFloat cornerRadius = MIN(size.width, size.height) * 0.5;
// 設置圓形路徑并切割
[[UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:cornerRadius] addClip];
// 將原始圖片繪制到圖形上下文中
[self drawInRect:rect];
// 從圖形上下獲取圖片
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
// 關閉圖形上下文
UIGraphicsEndImageContext();
// 返回圓形圖片
return image;
}
效果圖:
這樣我們在設置圖片時,即沒有拉伸,也沒有做透明度的混合,當我們在使用Tableview滾動時,就不再會需要對圖片執行額外的處理
最后,相對于CPU的處理速度來講,整個圖片處理的過程相當于一個耗時操作,所以我們可以將整個圖片過程放到異步執行
// 生成圓角圖片(優化后)
- (void)js_cornerImageWithSize:(CGSize)size fillClolor:(UIColor *)fillColor completion:(void(^)(UIImage *img))completion{
dispatch_async(dispatch_get_global_queue(0, 0), ^{
// 獲取開始時間
CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
// 開啟圖形上下文
UIGraphicsBeginImageContextWithOptions(size, YES, 0.0);
// 設置rect
CGRect rect = CGRectMake(0, 0, size.width, size.height);
// 設置填充色
[fillColor set];
UIRectFill(rect);
// 計算半徑
CGFloat cornerRadius = MIN(size.width, size.height) * 0.5;
// 設置圓形路徑并切割
[[UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:cornerRadius] addClip];
// 將原始圖片繪制到圖形上下文中
[self drawInRect:rect];
// 從圖形上下獲取圖片
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
// 關閉圖形上下文
UIGraphicsEndImageContext();
// 獲取結束時間
CFAbsoluteTime end = CFAbsoluteTimeGetCurrent();
//打印時間
NSLog(@"%f",end - start);
// 返回圓形圖片
// return image;
// 返回主線程
dispatch_async(dispatch_get_main_queue(), ^{
if (completion) {
completion(image);
}
});
});
}
這樣我們就通過模擬器判斷了程序的執行性能并進行了性能上的優化