[iOS Animation]-CALayer 性能优化实例
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
一個(gè)可用的案例
現(xiàn)在我們已經(jīng)對(duì)Instruments中動(dòng)畫性能工具非常熟悉了,那么可以用它在現(xiàn)實(shí)中解決一些實(shí)際問題。
我們創(chuàng)建一個(gè)簡(jiǎn)單的顯示模擬聯(lián)系人姓名和頭像列表的應(yīng)用。注意即使把頭像圖片存在應(yīng)用本地,為了使應(yīng)用看起來更真實(shí),我們分別實(shí)時(shí)加載圖片,而不是用–imageNamed:預(yù)加載。同樣添加一些圖層陰影來使得列表顯示得更真實(shí)。清單12.1展示了最初版本的實(shí)現(xiàn)。
清單12.1 使用假數(shù)據(jù)的一個(gè)簡(jiǎn)單聯(lián)系人列表
#import?"ViewController.h"#import?<QuartzCore/QuartzCore.h>@interface?ViewController?()?<UITableViewDataSource>@property?(nonatomic,?strong)?NSArray?*items; @property?(nonatomic,?weak)?IBOutlet?UITableView?*tableView;@end@implementation?ViewController-?(NSString?*)randomName {NSArray?*first?=?@[@"Alice",?@"Bob",?@"Bill",?@"Charles",?@"Dan",?@"Dave",?@"Ethan",?@"Frank"];NSArray?*last?=?@[@"Appleseed",?@"Bandicoot",?@"Caravan",?@"Dabble",?@"Ernest",?@"Fortune"];NSUInteger?index1?=?(rand()/(double)INT_MAX)?*?[first?count];NSUInteger?index2?=?(rand()/(double)INT_MAX)?*?[last?count];????return?[NSString?stringWithFormat:@"%@?%@",?first[index1],?last[index2]]; }-?(NSString?*)randomAvatar {NSArray?*images?=?@[@"Snowman",?@"Igloo",?@"Cone",?@"Spaceship",?@"Anchor",?@"Key"];NSUInteger?index?=?(rand()/(double)INT_MAX)?*?[images?count];????return?images[index]; }-?(void)viewDidLoad {[super?viewDidLoad];????//set?up?dataNSMutableArray?*array?=?[NSMutableArray?array];????for?(int?i?=?0;?i?<?1000;?i++)?{//add?name[array?addObject:@{@"name":?[self?randomName],?@"image":?[self?randomAvatar]}];}self.items?=?array;????//register?cell?class[self.tableView?registerClass:[UITableViewCell?class]?forCellReuseIdentifier:@"Cell"]; }-?(NSInteger)tableView:(UITableView?*)tableView?numberOfRowsInSection:(NSInteger)section {????return?[self.items?count]; }-?(UITableViewCell?*)tableView:(UITableView?*)tableView?cellForRowAtIndexPath:(NSIndexPath?*)indexPath {????//dequeue?cellUITableViewCell?*cell?=?[self.tableView?dequeueReusableCellWithIdentifier:@"Cell"?forIndexPath:indexPath];????//load?imageNSDictionary?*item?=?self.items[indexPath.row];NSString?*filePath?=?[[NSBundle?mainBundle]?pathForResource:item[@"image"]?ofType:@"png"];????//set?image?and?textcell.imageView.image?=?[UIImage?imageWithContentsOfFile:filePath];cell.textLabel.text?=?item[@"name"];????//set?image?shadowcell.imageView.layer.shadowOffset?=?CGSizeMake(0,?5);cell.imageView.layer.shadowOpacity?=?0.75;cell.clipsToBounds?=?YES;????//set?text?shadowcell.textLabel.backgroundColor?=?[UIColor?clearColor];cell.textLabel.layer.shadowOffset?=?CGSizeMake(0,?2);cell.textLabel.layer.shadowOpacity?=?0.5;????return?cell; }@end
?
當(dāng)快速滑動(dòng)的時(shí)候就會(huì)非常卡(見圖12.7的FPS計(jì)數(shù)器)。
圖12.7 滑動(dòng)幀率降到15FPS
僅憑直覺,我們猜測(cè)性能瓶頸應(yīng)該在圖片加載。我們實(shí)時(shí)從閃存加載圖片,而且沒有緩存,所以很可能是這個(gè)原因。我們可以用一些很贊的代碼修復(fù),然后使用GCD異步加載圖片,然后緩存。。。等一下,在開始編碼之前,測(cè)試一下假設(shè)是否成立。首先用我們的三個(gè)Instruments工具分析一下程序來定位問題。我們推測(cè)問題可能和圖片加載相關(guān),所以用Time Profiler工具來試試(圖12.8)。
圖12.8 用The timing profile分析聯(lián)系人列表
?-tableView:cellForRowAtIndexPath:?中的CPU時(shí)間總利用率只有~28%(也就是加載頭像圖片的地方),非常低。于是建議是CPU/IO并不是真正的限制因素。然后看看是不是GPU的問題:在OpenGL ES Driver工具中檢測(cè)GPU利用率(圖12.9)。
圖12.9 OpenGL ES Driver工具顯示的GPU利用率
渲染服務(wù)利用率的值達(dá)到51%和63%。看起來GPU需要做很多工作來渲染聯(lián)系人列表。
為什么GPU利用率這么高呢?我們來用Core Animation調(diào)試工具選項(xiàng)來檢查屏幕。首先打開Color Blended Layers(圖12.10)。
圖12.10 使用Color Blended Layers選項(xiàng)調(diào)試程序
屏幕中所有紅色的部分都意味著字符標(biāo)簽視圖的高級(jí)別混合,這很正常,因?yàn)槲覀儼驯尘霸O(shè)置成了透明色來顯示陰影效果。這就解釋了為什么渲染利用率這么高了。
那么離屏繪制呢?打開Core Animation工具的Color Offscreen - Rendered Yellow選項(xiàng)(圖12.11)。
圖12.11 Color Offscreen–Rendered Yellow選項(xiàng)
所有的表格單元內(nèi)容都在離屏繪制。這一定是因?yàn)槲覀兘o圖片和標(biāo)簽視圖添加的陰影效果。在代碼中禁用陰影,然后看下性能是否有提高(圖12.12)。
圖12.12 禁用陰影之后運(yùn)行程序接近60FPS
問題解決了。干掉陰影之后,滑動(dòng)很流暢。但是我們的聯(lián)系人列表看起來沒有之前好了。那如何保持陰影效果而且不會(huì)影響性能呢?
好吧,每一行的字符和頭像在每一幀刷新的時(shí)候并不需要變,所以看起來UITableViewCell的圖層非常適合做緩存。我們可以使用shouldRasterize來緩存圖層內(nèi)容。這將會(huì)讓圖層離屏之后渲染一次然后把結(jié)果保存起來,直到下次利用的時(shí)候去更新(見清單12.2)。
清單12.2 使用shouldRasterize提高性能
-?(UITableViewCell?*)tableView:(UITableView?*)tableView?cellForRowAtIndexPath:(NSIndexPath?*)indexPath {????//dequeue?cellUITableViewCell?*cell?=?[self.tableView?dequeueReusableCellWithIdentifier:@"Cell"forIndexPath:indexPath];...????//set?text?shadowcell.textLabel.backgroundColor?=?[UIColor?clearColor];cell.textLabel.layer.shadowOffset?=?CGSizeMake(0,?2);cell.textLabel.layer.shadowOpacity?=?0.5;????//rasterizecell.layer.shouldRasterize?=?YES;cell.layer.rasterizationScale?=?[UIScreen?mainScreen].scale;????return?cell; }
?
我們?nèi)匀浑x屏繪制圖層內(nèi)容,但是由于顯式地禁用了柵格化,Core Animation就對(duì)繪圖緩存了結(jié)果,于是對(duì)提高了性能。我們可以驗(yàn)證緩存是否有效,在Core Animation工具中點(diǎn)擊Color Hits Green and Misses Red選項(xiàng)(圖12.13)。
圖12.13 Color Hits Green and Misses Red驗(yàn)證了緩存有效
結(jié)果和預(yù)期一致 - 大部分都是綠色,只有當(dāng)滑動(dòng)到屏幕上的時(shí)候會(huì)閃爍成紅色。因此,現(xiàn)在幀率更加平滑了。
所以我們最初的設(shè)想是錯(cuò)的。圖片的加載并不是真正的瓶頸所在,而且試圖把它置于一個(gè)復(fù)雜的多線程加載和緩存的實(shí)現(xiàn)都將是徒勞。所以在動(dòng)手修復(fù)之前驗(yàn)證問題所在是個(gè)很好的習(xí)慣!
總結(jié)
在這章中,我們學(xué)習(xí)了Core Animation是如何渲染,以及我們可能出現(xiàn)的瓶頸所在。你同樣學(xué)習(xí)了如何使用Instruments來檢測(cè)和修復(fù)性能問題。
轉(zhuǎn)載于:https://my.oschina.net/u/2438875/blog/508123
總結(jié)
以上是生活随笔為你收集整理的[iOS Animation]-CALayer 性能优化实例的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 梦到很多肉是什么意思
- 下一篇: 梦到家里好多蟑螂什么意思