2019独角兽企业重金招聘Python工程师标准>>>

一个可用的案例

现在我们已经对Instruments中动画性能工具非常熟悉了,那么可以用它在现实中解决一些实际问题。

我们创建一个简单的显示模拟联系人姓名和头像列表的应用。注意即使把头像图片存在应用本地,为了使应用看起来更真实,我们分别实时加载图片,而不是用–imageNamed:预加载。同样添加一些图层阴影来使得列表显示得更真实。清单12.1展示了最初版本的实现。

清单12.1 使用假数据的一个简单联系人列表

#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

当快速滑动的时候就会非常卡(见图12.7的FPS计数器)。

图12.7 滑动帧率降到15FPS

仅凭直觉,我们猜测性能瓶颈应该在图片加载。我们实时从闪存加载图片,而且没有缓存,所以很可能是这个原因。我们可以用一些很赞的代码修复,然后使用GCD异步加载图片,然后缓存。。。等一下,在开始编码之前,测试一下假设是否成立。首先用我们的三个Instruments工具分析一下程序来定位问题。我们推测问题可能和图片加载相关,所以用Time Profiler工具来试试(图12.8)。

图12.8 用The timing profile分析联系人列表

-tableView:cellForRowAtIndexPath: 中的CPU时间总利用率只有~28%(也就是加载头像图片的地方),非常低。于是建议是CPU/IO并不是真正的限制因素。然后看看是不是GPU的问题:在OpenGL ES Driver工具中检测GPU利用率(图12.9)。

图12.9 OpenGL ES Driver工具显示的GPU利用率

渲染服务利用率的值达到51%和63%。看起来GPU需要做很多工作来渲染联系人列表。

为什么GPU利用率这么高呢?我们来用Core Animation调试工具选项来检查屏幕。首先打开Color Blended Layers(图12.10)。

图12.10 使用Color Blended Layers选项调试程序

屏幕中所有红色的部分都意味着字符标签视图的高级别混合,这很正常,因为我们把背景设置成了透明色来显示阴影效果。这就解释了为什么渲染利用率这么高了。

那么离屏绘制呢?打开Core Animation工具的Color Offscreen - Rendered Yellow选项(图12.11)。

图12.11 Color Offscreen–Rendered Yellow选项

所有的表格单元内容都在离屏绘制。这一定是因为我们给图片和标签视图添加的阴影效果。在代码中禁用阴影,然后看下性能是否有提高(图12.12)。

图12.12 禁用阴影之后运行程序接近60FPS

问题解决了。干掉阴影之后,滑动很流畅。但是我们的联系人列表看起来没有之前好了。那如何保持阴影效果而且不会影响性能呢?

好吧,每一行的字符和头像在每一帧刷新的时候并不需要变,所以看起来UITableViewCell的图层非常适合做缓存。我们可以使用shouldRasterize来缓存图层内容。这将会让图层离屏之后渲染一次然后把结果保存起来,直到下次利用的时候去更新(见清单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;
}

我们仍然离屏绘制图层内容,但是由于显式地禁用了栅格化,Core Animation就对绘图缓存了结果,于是对提高了性能。我们可以验证缓存是否有效,在Core Animation工具中点击Color Hits Green and Misses Red选项(图12.13)。

图12.13 Color Hits Green and Misses Red验证了缓存有效

结果和预期一致 - 大部分都是绿色,只有当滑动到屏幕上的时候会闪烁成红色。因此,现在帧率更加平滑了。

所以我们最初的设想是错的。图片的加载并不是真正的瓶颈所在,而且试图把它置于一个复杂的多线程加载和缓存的实现都将是徒劳。所以在动手修复之前验证问题所在是个很好的习惯!

总结

在这章中,我们学习了Core Animation是如何渲染,以及我们可能出现的瓶颈所在。你同样学习了如何使用Instruments来检测和修复性能问题。

转载于:https://my.oschina.net/u/2438875/blog/508123

[iOS Animation]-CALayer 性能优化实例相关推荐

  1. iOS最全性能优化(中)

    续 性能优化(上) 9. 重用和延迟加载(lazy load) Views 更多的view意味着更多的渲染,也就是更多的CPU和内存消耗,对于那种嵌套了很多view在UIScrollView里边的ap ...

  2. 分享一个SQLite 性能优化实例

    本文给大家分享的是个人在实际项目中对于sqlite的一次优化的记录,非常简单实用,希望对大家学习sqlite能够有所帮助. 最早接触 iOS 开发了解到的第一个缓存数据库就是 SQLite,后面一直也 ...

  3. iOS App 启动性能优化

    为什么80%的码农都做不了架构师?>>>    本文来自于腾讯Bugly公众号(weixinBugly),未经作者同意,请勿转载,原文地址:https://mp.weixin.qq. ...

  4. Android ListView性能优化实例讲解

    前言: 对于ListView,大家绝对都不会陌生,只要是做过Android开发的人,哪有不用ListView的呢? 只要是用过ListView的人,哪有不关心对它性能优化的呢? 关于如何对ListVi ...

  5. iOS 10 UICollectionView 性能优化

    前言 关于 iOS 10 UICollectionView的新特性,主要还是体现在如下3个方面 顺滑的滑动体验 现在基本上人人都离不开手机,手机的app也每天都有人在用.一个app的好坏由它的用户体验 ...

  6. apache php 调优_Apache的性能优化实例(一)

    本文主要和大家分享Apache的性能优化(一),希望能帮助到大家. Apache缺省的最大用户数是256个:这个配置对于服务器内存还是256M左右的时代是一个非常好的缺省设置,但随着内存成本的急剧下降 ...

  7. iOS最全性能优化(下)

    续 性能优化(中) 22. 加速启动时间 快速打开app是很重要的,特别是用户第一次打开它时,对app来讲,第一印象太太太重要了. 你能做的就是使它尽可能做更多的异步任务,比如加载远端或者数据库数据, ...

  8. [iOS Animation]-CALayer 变换

    变换 很不幸,没人能告诉你母体是什么,你只能自己体会 -- 骇客帝国 在第四章"可视效果"中,我们研究了一些增强图层和它的内容显示效果的一些技术,在这一章中,我们将要研究可以用来对 ...

  9. iOS开发之性能优化

    1.避免过于庞大的XIB 当加载XIB的时候把所有的东西都放在了内存里,包括任何的图片:如果有一个不会即刻用到的view,就会浪费宝贵的内存资源了. 当加载一个引用了图片或者声音资源的nib时,nib ...

最新文章

  1. 迭代var()内置函数的时候出现RuntimeError: dictionary changed size during iteration的解决办法...
  2. 五子棋html游戏代码与算法介绍
  3. app 模拟器抓包 burpsuite_安全测试扫描利器Burpsuite
  4. eclipsejvm内存不足_Eclipse无法调试及编译时内存不足的解决
  5. 360产品演示代码 css3 html5,HTML5 CSS3代码的三维展示
  6. 得物App获得2020“年度新经济企业”奖项
  7. 29. Element ownerDocument 属性
  8. Linux学习篇之权限管理
  9. java怎么反编译_java如何进行反编译
  10. 雨听|Vs Code中使用markdown语法实现mac风格的代码块
  11. c语言常用函数doc下载,c语言常用函数.doc
  12. ExoPlayer播放器播放MP2音频格式视频无声音加入Ffmpeg软解码功能
  13. java工具类书写规范
  14. 在Storyboard中设置borderColor
  15. 章节1 计算机体系结构
  16. 开源移动设备管理(MDM)解决方案的利与弊
  17. chrome与chromedriver版本对应关系以及官方下载页面
  18. 2019河北单招计算机考试模拟试题,2019年河北单招文科数学模拟试题(一)【含答案】.docx...
  19. 卷积神经网络是如何实现不变性特征提取的?
  20. AirPods Pro 2出现随机断连问题,充电仓支持Find My成最大亮点

热门文章

  1. centos7 docker删除端口映射_容器Docker详解
  2. cocos2dx 字体外发光_在电致发光研发领域,选择有机材料是基于哪些原因?
  3. Ubuntu14.04设置开机可以以root用户身份登录
  4. golang实现聊天室(四)
  5. linux操作系统信号捕捉函数之回调函数小结
  6. 数据库原理及应用【五】安全性和完整性约束
  7. 树链剖分入门+HYSBZ - 1036树的统计Count
  8. Socket网络编程--小小网盘程序(1)
  9. 剑指Offer05. 替换空格
  10. TCP send 阻塞与非阻塞