当你拿到这本书的时候我默认你是一个iOS开发者或者已经开发应用程序很长一段时间了,并且愿意从另外一个开发联盟加入进来。
在这一章中我们主要领略下高性能app中的一些概念。
定义性能
从技术的角度讲,性能是经常被提起的一个模糊的话题,经常有些人说高性能应用程序但是我们确不知道他们真正在说什么,可能是说用了更少的内存,节省了网络流量的使用,或者使用流畅等。
对于我来说,当谈到高性能的时候,我将从多个方面来讨论,一部分是性能的定义,另外我们想要衡量和各种的东西,最后是通过搜集数据来测量验证
在这一章中我们将探讨性能的定义接下来我们将讨论性能的测量,我们将深入的探索测量过程。
性能定义
内存
对于内存,我将从应用程序消耗的最低内存,平均和最大内存开始讨论,最小内存对硬件做了一个限制,高的平均内存意味着很多后台程序将会被杀死,最大内存将增加应用后台内存超出的几率。
也就是说,你一定要确保内存不要泄露,如果内存随着时间的推移持续增加那么意味着程序可能崩溃抛出内存不足异常。
电量消耗
这是另外一个实现高性能代码的因素,不仅你的数据结构和算法要高效而且还需要考虑其他因素,如果你的应用是耗尽电量,那我确定没有喜欢用它。
电量消耗不仅仅是关注CPU计算周期,同时也是高效实用硬件。
因此需要谨慎的构造代码,在减少电量消耗决策之前,同时要确保不要降低用户体验。
启动时间
你平时打开一个app需要多长时间还是你自是安装从来不打开?
当我们自己的app给别人用的时候,你可能需要初始化很多任务在用户使用前,但是一直有争议的 ,延迟初始化是一个很好的策略用户在执行后续任务的时候不应该每次都等待。
下面是一些你可能在初始化做的事情:
- 检查app是不是第一次加载;
- 检查用户是否登录;
- 如果用户已经登录如果可以的话加载之前的状态;
- 连接服务器获取最新的更改
- 检查应用底层是否加载完成,如果完成加载UI和状态
- 检查上一次是否有挂起的任务,如果需要的话就恢复
- 初始化后续需要用到的对象和线程池
- 初始化关联东西,例如ORM 崩溃报告系统缓存等。
初始化的事情一直在增加,很难决定是应该启动的时候加载还是延迟加载。
执行速度
一旦用户在使用一个app,他希望尽可能流畅的,任何执行过程都应该很少时间。
例如一个拍照app,我做的任何编辑我都想在很短的时间看到结果。我不想花时间讨论。
对于一些简单的效果,例如改版亮度或者对比度,如果能在我调整的时候看到预览的效果那最好了,因此他就需要我们在更短的时间内处理完成。
建议:对于一个长时间的运行过程总是应该用一个进度来显示这个过程,无论是费时的计算还是下载内容
响应性
你的应用程序应该快速的响应用户的操作,响应性是所有优化的结果 权衡你在程序中做的事情。
有如此多的应用在争取用户的关注,你通常有少于一分钟的时间让你的应用进入用户的首选应用列表,时间限制是非常严格的,如果有很多程序提供了同样的功能,如果你能再第一步加载的时候消耗更少的时间,那进入用户的首选列表的转换成本就会很小。
例如我在商店搜索2048游戏的时候,我至少搜索到了超过半打的应用,因为我不确定用哪个所以我下载了所有的然后删除他们最后留下一个。有很多原因起到作用,加载时间、用户体验、比其他的更好的平滑动画等待,每个应用有15秒让我留下印象。
本地存储
任何应用都都是存储数据在服务器或者另外的数据源,但是必须要有一个离线的本地存储计划。
我希望我的邮件app至少能显示我已经阅读过的邮件在离线或者没有网络的时候。
同样一个新闻app也应该能够在离线模式下显示上次更新的新闻,以及一些提示对每个新闻条目表明什么事新的和我已经准备读的,如果我不要订阅我也不需要登录。
然而,从本地加载数据应该是快速的,这不仅要求我们选择本地缓存而且还要考虑数据结构,选择远程同步频率等。
任何应用一直占用本地存储但是没有一个清理功能对我来说是最糟糕的,令人遗憾的是,大多数在市场上的应用都没有这个功能,更让我悲哀的是,下面图表中的应用很多都使用本地存储在几百兆,所以当我耗尽空间的时候,我只是删除这些应用很长一段时间不在下载他们。
图-1
从图1中我们可以看出,超过12G的空间已经被使用了只留下950M的可使用空间,我是不高兴的对于Facebook使用了250M而没有提供一个清理按钮。唯一的清理办法就是删除app,另外一个Google+是只用了5M到目前为止是挺好的,但是他也没有提供一个清理按钮。
出于这个原因,如果我安装的社交应用像WhatsApp或者Viber如果他们存储多媒体数据但是没有提供清除按钮,我不会打开摄像头权限,如果他占用很多空间,我宁愿不使用app中的多媒体功能或者直接卸载它。
建议:总是应该给终端用户提供一个清除缓存按钮。
交互性
iOS提供多种交互操作在app之间共享数据,UIActivityViewController、deeplinking,MultipeerConnectivity框架都是可以使用的
定义一个类良好的URL结构对于写好代码来解析它是非常重要的,同样也适用于分享数据。
如果你的应用需要花很长的时间来准备数据共享到附近的设备上,那将是一个很糟糕的体验。
网络情况
应用应该工作在所有网络情况下:
- 高带宽稳定网络
- 低带宽稳定网络
- 高带宽不稳定网络
- 低带宽不稳定网络
- 无网络
给用户一个提示或者错误消息是很好的,但是不能让用户无限的等待或者程序崩溃。
图2
图2显示了不同的方式来呈现消息给用户,TuneIn应用显示了多少流媒体内容已经缓存,它告诉用户还需要等待多久才能开始播放音乐。另外像MoneyControl或者Bank of America应用它提供了一个不确定的进度条,它更适用于没有流媒体的应用。
带宽
人们使用手机不仅在wifi情况下同时还是用移动网络LTE\3G\2G等,根据维基百科一篇文章统计的各个国家的网络情况,全世界平均带宽3.8M/S,韩国最快21.9M/S,玻利维亚最慢1M/S.
因此优化使用带宽是另外一个衡量产品好坏的因素,还请记住,如果你已经在低带宽下开发了程序,运行在高带宽的时候可能产生不同的结果。
我记得2010年我和一个大部分人员在印度开发团队开发一个应用,网络带宽是很糟糕的需要花很长的时间初始化,因此对于这种情况我们改变了程序市场。
然而当我们在韩国市场测试的时候出现了完全不同的结果,我们没有做任何优化和权衡工作,因此我们需要写大量的代码来避免可能发生的资源和数据竞争。
因此打算实现高性能并不总是优化的结果,有时候评估也会导致。
数据刷新
即使你没有任何的离线浏览功能,你也需要一直定期的来刷新数据,数据刷新的频率和传输的字节都会影响整个流量的消耗,如果这个传输的字节足够大,用户肯定会耗尽他的流量,如果这个值足够大,那么你可能已经失去了一个用户。
iOS6.x的应用是不能再后台刷新数据的,从iOS7开始,应用可以使用后台程序刷新,对于实时聊天应用一个持久的HTTP或者TCP链接可能是更有用的。
多账户管理
对于一个家庭来说共用一台手机是很平常的。例如两个孩子可能用同一个iPad玩游戏,其中一个人可能想要在假期期间配置一台设备来查看每个人的邮件来减少个人的漫游费用,特别是真正国际旅行期间。
决定支持多用户完全是一个产品决定的,但是如果你决定要支持,请确保:
- 用户加载高效
- 用户更新高效
- 用户切换高效
- 用户边界应该清楚的并且没有任何bug
图3
单点登录
如果有一个或多个应用允许或要求登录,单点登录总是一个好主意,因此如果我在一个应用中已经登录,那么在其他应用只需要点击登录就可以。
现在,在跨应用之间不仅要同步数据,还要同步状态等等,因此如果我在其他应用登出了没那么之前登录的也应该显示登出状态。
所有的可能执行的逻辑都应该高效且安全的。
安全性
安全是非常重要的对于几个一起安装的移动应用,应该确保相互通信,本地数据保护和所有的表单数据安全,他们都是应用共享数据安全的关键属性。
加密是一个不错的选择,但是他增加了处理数据的时间,更不要说内存的消耗了。
因此你需要权衡速度和加密,但是他们两者的平衡点的一个关键因素是用户体验,注意,硬件也扮演一个重要的角色,在iPhone4上面做的优化和注意事项可能在iPhone5C 5S上的结果是完全不同的。
崩溃
应用可能会崩溃,一定会崩溃,过度的优化可能也会导致崩溃,使用C代码也可能导致崩溃。
一个高性能的应用应该能在崩溃的时候保护自己,并且还能优雅的恢复,例如一些在崩溃中发生的操作。
项目:高性能
例子创建步骤不翻译
事列:vCircle
vCircle是我们构建的一个基础网络社交app,它支持以下功能:
- 登录Facebook
- 支持多账户
- 显示最新提示
- 显示一条信息包括图像或者所有评论
- 检索用户的所有带评论和标记的照片
- 允许添加评论到朋友的状态或照片
- 支持无线滚动
我们建立vCircle项目重点是关注性能,功能可能有些没有完成,但是我们会完成所有有关性能的代码。
并且我们不会使用Facebook或者其他功能性的SDK 我们尽量自己写代码,用SDK的一些基础常见功能。
我们将会用到CocoaPods,如果你不熟悉它,你可能要停下来学习下它。
我们在本书的后面将开始使用这个程序。
这个代码你可从github上下载
备注:这章翻译基于早期的版本 所以内容和下载链接有区别,后续章节将基于最新版本。