本书因为是翻译过来,有些地方翻译的并不尽善尽美,所以在笔记中会进行一些修改,如名词的翻译。在我认为有意义的地方,会将原文和翻译一并放上来。
作为一个iOS开发者,我们时刻都要关心应用的体验,加入给了用户不好的体验,可能这个用户就会永远的失去,并且讲这个糟糕的消息告诉自己的亲朋好友。
- 一项研究表明,如果应用无法在三秒内加载启动,那么约四分之一的用户将放弃此应用,约三分之一的用户会将这段令人不快的经历转告他人。
先来看一组调研数据
- 应用首次启动 出错以后,79% 的用户只会在重试一两次
- 当应用载入时间超过3秒时,25%的用户放弃使用该应用
- 31%的用户会将糟糕的体验告诉其他人
以上的调研数据都强调了性能对于应用的重要性
性能会受到很多因素的影响,这些因素包括内存消耗, 网络宽带效率以及用户界面的相应速度.我们先概述不同类型的性能特征,然后在对他们进行测量。
1.性能指标
性能指标是面向用户的各种属性,每个属性可能是一个或多个测量工程参数的一个要素。
1.1 内存
内存涉及运行应用所需的 RAM 最小值,以及应用消耗的内存平均值和峰值.最小内存值会严重限制硬件,而最高的内存平均值和峰值意味着更多的后台应用会被强制关闭。
同时还用确保没有内存泄露, 随时间流逝而持续增长的内存消耗意味着,应用很可能会因为内存不足的异常而崩溃
1.2 电量消耗
在编写高性能 代码时, 电量消耗是一个需要重点处理的重要因素, 就执行时间和 CPU 资源的利用而言, 我们不仅要实现高效的数据结构和算法, 还需要考虑其他的因素,如果你的应用是个电池黑洞,那么一定不会有人喜欢他。
If your app drains battery, rest assured that no one will appreciate it.
电量消耗不仅仅与计算 CPU 周期有关,还包括高效的使用硬件, 除了要实现电量消耗最小化, 还要确保不会影响用户体验
1.3 初始化时间
应用在启动时应执行刚好够用的任务以完成初始化, 从而满足用户的使用需求,执行这些消耗的时间就是应用的初始化时间, "搞好够用"是一个开放式用语------正确的平衡点取决于应用的需要。
在首次使用应用时 创建对象并进行初始化是一个合理的选择, 例如:直到需要使用对象时,才创建对象, 这种方式叫做懒加载 (lazy initialization)。
下面列举了 你可能想在应用初始化阶段执行的一些动作:
- 检查应用是否是首次启动
- 检查用户是否已经登录
- 如果用户已经登录, 尽可能地载入之前的状态
- 连接服务器以拉取最新的变更
- 检查应用是否由某个深层链接唤起.如果是,还需要载入深层链接相应的 UI 和状态
- 检查是否存在应用上次启动时 挂起的任务,需要时恢复他们
- 初始化后续需要使用的对象和线程池
- 初始化依赖项(如对象关系映射, 崩溃报告和缓存)
1.4 执行速度
一旦启动应用, 用户总是希望他可以尽可能快的工作,一切必要的处理都应该在尽可能短的时间内完成 。
例如 在照片应用中, 用户通常希望看到调整高度或对比度等简单效果的实时预览效果 因此相应的处理需要在几毫秒内完成。
1.5 响应速度
每个应用都应该快速的响应用户交互, 在应用中所做的一切优化和权衡最终都体现在相应速度上。
App Store中有需要应用可以完成相似或者相关的任务, 这位用户提供了很大的选择空间,而用户基本都会选择相应最快的应用。
1.6 本地存储
针对任何在服务器上存储数据或通过外部来源刷新数据的应用,开发人员应该对本地存储的使用有所规划.以便应用具备离线浏览的能力。
如果你的应用使用了本地存储,那么请提供一个清除数据的选项,遗憾的是,市场上的大部分应用都没有提供此选项,更让人烦恼的是,一些应用竟然会消耗数百兆的存储空间,用户会频繁的卸载这些应用来回收本地存储, 这回导致糟糕的用户体验,从而威胁应用的成功
一定要向终端用户提供清空本地缓存的选项
1.7 互操作性
这个知识点主要应用在多个应用互相操作的情况。
用户可能会使用多个应用来完成某个任务, 这就需要这些应用直接提供互操作的能力, 如一个相册可能需要一个幻灯片应用来实现最佳的浏览效果,但需要另一个应用来编辑照片, 其中浏览照片的应用要能够将照片发送到编辑器,并接收编辑后的图片
IOS 为实现应用间的互操作和数据共享提供了多种机制,其中包括 UIActivityViewController,深层链接, MulipeerConnetivity框架,等等。
为深层链接定义良好的 URL 结构与编写优异的代码来解析 URL 同样重要,类似的使用共享对话框共享数据时,精确识别用于分享的数据非常重要,同时在处理不同数据源传入的数据时还有注意安全隐患
1.8 网络环境
移动设备会在不同网络环境下使用, 为了确保能够提供最好的用户体验,你的应用应当适应各种网络条件
- 高宽带稳定网络
- 低宽带稳定网络
- 高宽带不稳定网络
- 高宽带不稳定网络
- 无网络
为用户提供进度指示或错误信息是相对合理的方式, 无尽的等待或崩溃则让人无法忍受 如图因网络差或数据量大而显示的不同提示信息
1.9 带宽
人们会在不同的网络条件下使用自己的移动设备,网速从每秒数千字节到每秒数十兆字节。
因此宽带的优化使用是定义应用质量的另一个关键参数,。此外,在高宽带网络下运行一个基于低宽带网络开发的应用可能产生完全不同的结果
Planning for high performance does not always result in optimizations, but can result in trade-offs as well.
为提高性能所做的设计并非每次都能如愿,也可能会导致相反的效果。
1.10 数据刷新
即使没有提供离线浏览能力,你仍可以从服务器端周期性的刷新数据,刷新的频率和每次传输的数据量将决定数据传输的总量,如果传输的字节数过大, 那用户必然会快速耗尽自己的流量。当流量消耗大到一定程度时, 你的应用很可能会流失用户。
从 iOS7 开始应用可以在后台周期性的刷新数据, 对于及时聊天应用,持久的 HTTP 链接或原生 TCP 链接可能会非常有用
1.11 多用户支持
是否支持多个并发用户取决于产品的需要, 一旦决定提供此功能,请参考以下准则:
- 添加新用户应尽可能高效
- 在不同用户之间更新应尽可能高效
- 在不同用户之间切换应尽可能高效
- 用户数据的界限应该简洁且没有 bug
1.12 单点登录
例如腾讯系列应用
如果你已经创建了多个允许或需要登录的应用, 那么支持单点登录就是一个很多的选择, 如果用户登录了一个应用, 只需要点一次,就可以登录到其他的应用中。
1.13 安全
安全对移动应用来说是最重要的, 因为敏感信息可能会在应用之间共享。因此 对所有通信以及本地数据和共享数据进行加密就显得尤为重要了。
但是引入多个安全层又会影响性能, 并对用户体验造成可感知的负面影响.如何设定安全的基线需要参考对用户群体的统计分析.此外,硬件在其中扮演了重要的角色,选择会因为不同设备的计算能力而有所不同
1.14 崩溃
高性能的应用不仅应尽可能的避免崩溃.还应该在崩溃发生时优雅的恢复, 尤其是在进行某个操作的过程中发生崩溃时。
2.应用性能分析方法
2.1 采样
顾名思义,采样(或基于探测点的性能分析)是指以一定的周期间隔采集状态,这通常需要借助工具。采样的不足之处在于它不能返回100%精确的细节。如果采样的频率是10毫秒,那么你就无法得知在探测点之间的9.999毫秒内发生了什么。
采样可以作为初始的性能调研手段,并可用于跟踪CPU和内存网使用情况。
2.2 埋点
通过修改代码,记录细节信息的埋点能够提供比采样更加精确的结果。你既可以在关健部分主动埋点,也可以在性能分析或处理用户反馈时有针对性地埋点,以便解决问题。
因为地点需要注入额外代码,所以它一定会影响应用的性能,对内存线速度(或同时对二者)造成损害。
3.如何测量
我们要通过测量性能并找出真正存在问题的地方,可以避免掉入过早优化的陷阱。
The real problem is that programmers have spent far too much time worrying about efficiency in the wrong places and at the wrong times; premature optimization is the root of all evil (or at least most of it) in programming.
真正的问题在于,开发者为提升程序效率在错误的方向和时间点浪费了太多时间;过早优化是编程领域的万恶(至少绝大多数的恶)之源。
3.1 设置工程和代码
良好,正确的设计工程和代码,并在以下几个方面设置,会有益于后续操作:
- 构建与发布
快速拉取依赖信息(如cocoaPods),加速构建和发布用于测试或企业分发的产品。 - 可测试性
顾名思义,良好的单元测试和功能测试。 - 可跟踪性
埋好点。
3.2 设置崩溃报告
使用成熟的第三方崩溃报告服务即可。
3.3 对应用埋点
这里可以使用第三方埋点,但是假如在有需求的情况下,如对某个页面进入时间持续时间或更加详细的信息。需要进行自行设置埋点。这里也可以分为侵入式和非侵入式埋点,各有优劣,这里并不展开。
埋点不应该取代日志,日志可以非常的详细。但因为向服务器报告时会消耗网络资源,所以应该尽可能的少埋点。
因此,只对你和其他工程或产品团队的成员感兴趣的事件进行埋点是非常重要的。(这些时间要包含足够多的数据以满族重要报告的需要)。
3.4 日志
日志是无价之宝,可以用于了解应用发生了什么事。
日志和埋点之间存在着细微的差别。埋点可以看作日志的子集。被埋点的任何数据都应该记录在日志中。
埋点承担了为聚合分析发布关键性能数据的职责,日志则提供了用于在不同级别跟踪应用的细节信息,比如debug、Verbose、info、warning和Error。日志的记录会贯穿应用的整个生命周期,而埋点只应该用在开发的特定阶段。
埋点数据会发送到服务器,日志是记录在设备本地。