良好的用户体验须要以下要素:数据库
电池寿命长。随着能效下降,电池寿命也会下降。但用户想让本身的移动设备全天候待命。缓存
速度快。iOS系统处理复杂操做时仍能提供很好的性能。服务器
响应快。同一时刻消耗太多资源会使UI卡顿,响应用户速度变慢。网络
温度低。app消耗的硬件资源的越多,系统工做越繁重,设备的温度就会逐渐上升。这时系统会经过一些措施下降设备温度。并发
iOS运用了不少先进的节能技术确保用户有很好的用户体验,包括软硬件配合优化、先进的App调度机制、网络延时操做、任务优先级管理机制等。app
App中很小的低效行为在整个系统中累加后,会对电池寿命、性能、响应速度和温度产生明显的影响。使用苹果推荐的API,以确保系统能够正确地判断如何更好地管理咱们的app和app使用的各类资源。分批、减小网络操做。尽量避免不须要的UI刷新。功耗大的操做应该在用户的控制之中。好比,若是用户正在玩一个视图很是复杂的大型游戏,电量消耗很快用户是能够理解的。不响应用户操做时,app尽可能不要执行任何操做。框架
基本概念less
没有一劳永逸地解决能耗问题的方案。不少技术和操做影响着电量的使用:异步
CPU。 CPU是电能消耗大户,高CPU使用量会迅速消耗掉用户的电池电量。app作的每件事几乎都须要用CPU,因此使用CPU要精打细算,真正有须要时经过分批、定时、有序地执行任务。函数
设备唤醒。iOS设备经过睡眠来节能。只要设备被唤醒,屏幕和其余的硬件资源就必须通电,会产生很高的间接功耗。如非必须,app要尽可能保持闲置,不要推送消息或用其余方式唤醒设备,特别是app在后台的时候。
网络操做。大多数app都须要网络操做。网络通讯时,蜂窝数据和Wi-Fi等元器件开始工做就会消耗电能。分批传输、减小传输、压缩数据、恰当地处理错误,你的app省电效果会很显著。
图像、动画、视频。app内容每次更新到屏幕上都须要消耗电能处理像素信息。动画和视频格外耗电。不经意的或者没必要要的内容更新一样会消耗电能,因此UI不可见时,应该避免更新其内容。
位置。不少app为了记录用户的活动或者提供基于位置的服务会进行定位。定位精度越高,定位时间越长,消耗电量也就越多。因此app应该尽可能下降定位精度、缩短定位时间。不须要位置信息以后当即中止定位。
动做传感器。长时间用不上加速度计、陀螺仪、磁力计等设备的动做数据时,应该中止更新数据,否则也会浪费电能。应按需获取,用完即停。
蓝牙。蓝牙活动频度过高会消耗电能,应该尽可能分批、减小数据轮询等操做。
简化、有序地工做
减小后台工做
实现UIApplicationDelegate中的方法,应用进入后台前作好暂停任务,保存数据等工做。若是确实须要完成用户执行的一些任务,应该调用UIApplicationDelegate中的beginBackgroundTaskWithExpirationHandler: 方法,这样后台任务能够继续执行几分钟。任务执行完毕后必定要调用endBackgroundTask:方法,不要等着系统强行挂起进程。
iOS8以后,系统引入了CPU监控机制,以观察后台app的CPU使用量是否超过了限制,若是超出限制,进程可能会被关闭。大多数状况下正常的后台任务不会遇到这种状况,若是遇到了能够查看崩溃日志信息,异常类型为EXC_RESOURCE,子类型为CPU_FATAL。
用QoS分级有序工做
多个app和众多操做须要共享CPU、缓存、网络等资源,为了保持高效,系统须要根据不一样任务的优先级智能地管理这些工做。好比更新UI这种重要的事须要多分配资源,而一些后台任务能够延迟一些执行。服务质量(quality of service, 如下简称QoS, iOS8引入)级别能够经过NSOperation, NSOperationQueue, NSThread objects, dispatch queues, 和pthreads (POSIX threads)指定工做的优先级。有4种QoS级别(和2种特殊的级别),如表2所示,划线的两个特殊的级别通常不该该使用,仅做了解便可。最好状况是,用户不交互的时候,90%以上的时间让app运行在Utility或更低级别。
原来GCD中的全局并发队列(global_queue)用高、默认、低、后台来指定队列的优先级。如今应该改用QoS,二者的对应关系如表。
少使用定时器
app常常滥用定时器。想一下你app中的定时器,是否真的有必要存在。抛开具体场景不说,若是定时器触发太频繁,能耗影响是比较大的。
用事件通知代替定时器。有些app用定时器监控文件内容、网络或者其余状态的变化,这会致使CPU没法进入闲置状态而增长功耗。建议使用事件通知来代替定时器,好比使用dispatch source监测文件变化。对于系统提供的服务,尽可能使用事件通知,表是常见的系统通知和对应的监测方法。
GCD里的dispatch queues、dispatch semaphores等同步工具比定时器效率高不少,尽可能不要用定时器作同步工具。
全部须要指定一个最后期限的函数或方法都属于定时器,好比:
1. 高级定时器包括dispatch timer sources、CFRunLoopTimerCreate和其余CFRunLoopTimer函数、NSTimer、performSelector:withObject:afterDelay:方法。
2. 底层定时器包括sleep, usleep, nanosleep, pthread_cond_timedwait, select, poll, kevent, dispatch_after, dispatch_semaphore_wait。
若是必定要用定时器,尽可能高效地使用,能够参照下列指导方针:
1. 设置一个合适的超时时间。
2. 再也不须要时及时关闭重复性定时器。
3. 设置触发公差。
优化I/O访问
app每次执行I/O任务,好比写文件,会致使系统退出闲置模式。并且写入缓存格外耗电。经过下列方法能够提升能效、改善app性能。
1. 减少写入数据。数据有变化再写文件,尽可能把多个更改攒到一块儿一次性写入。若是只有几个字节的数据改变,不要把整个文件从新写入一次。若是你的app常常要修改大文件里不多的内容,能够考虑用数据库存储这些数据。
2. 避免访问存储频度过高。若是app要存储状态信息,要等到状态信息有变化时再写入。尽可能分批修改,不要频繁地写入这些小变更。
3. 尽可能顺序读写数据。在文件中跳转位置会消耗一些时间。
4. 尽可能从文件读写大数据块,一次读取太多数据可能会引起一些问题。好比,读取一个32M文件的所有内容可能会在读取完成前触发内容分页。
5. 读写大量重要数据时,考虑用dispatch_io,其提供了基于GCD的异步操做文件I/O的API。用dispatch_io系统会优化磁盘访问。
6. 若是你的数据由随机访问的结构化内容组成,建议将其存储在数据库中,可使用SQLite或Core Data访问。特别是须要操做的内容可能增加到超过几兆的时候。
7. 了解系统如何缓存文件、如何优化缓存的使用。若是你不打算屡次引用某些数据,不要本身缓存数据。
低电量模式
iOS9以后,iPhone增长了低电量模式,用户若是但愿延长iPhone电池的寿命,能够在设置 > 电池中开启该功能。开启该功能以后iOS会采起一些措施,好比:
1. 下降CPU和GPU性能
2. 暂停随意的和后台的活动,包括网络
3. 下降屏幕亮度
4. 缩短自动锁屏时间
5. 关闭邮件刷新
6. 关闭视角缩放
7. 关闭动态壁纸
你的app也应该作一些事情帮助系统节省电能,好比,能够减小动画、下降帧率、中止位置更新、关闭同步和备份功能等等。能够经过向NSNotificationCenter注册NSProcessInfoPowerStateDidChangeNotification 通知监听低电量模式状态。
网络操做
只要app一执行网络操做,就会产生大量间接能耗(overhead cost)。网络硬件,好比蜂窝数据和Wi-Fi电路,为了省电默认是不通电的。为了执行网络操做,这些资源必须通电,以后为了等待接下来可能出现的任务,它们在操做完成后会继续保持一段时间的活跃。零散的网络传输会致使很高的间接能耗,迅速消耗电池电量
缩减网络请求
1. 减小、压缩网络数据。能够下降上传或下载的多媒体内容质量和尺寸等。
2. 使用缓存,不要重复下载相同的数据。
3. 使用断点续传,不然网络不稳定时可能屡次传输相同的内容。
4. 网络不可用时不要尝试执行网络请求,尽可能只在Wi-Fi状况下联网。
5. 让用户能够取消长时间运行或者速度很慢的网络操做,设置合适的超时时间。
6. 网络请求失败后用SCNetworkReachability的通知监测网络状态,网络可用后再重试。
延迟联网
分批传输。好比,下载视频流时,不要传输很小的数据包,直接下载整个文件或者一大块一大块地下载。若是提供广告,一次性多下载一些,而后再慢慢展现。若是要从服务器下载电子邮件,一次下载多条,不要一条一条地下载。
网络操做能推迟就推迟。若是经过HTTP上传、下载数据,建议使用NSURLSession中的后台会话,这样系统能够针对整个设备全部的网络操做优化功耗。将能够推迟的操做尽可能推迟到设备充电状态而且链接Wi-Fi时进行,好比同步和备份工做。
VoIP类应用应该用PushKit而不是长链接。
图像、动画、视频
如下列指导方针优化内容更新:
1. 减小app使用的视图数量。
2. 减小不透明视图的使用,好比视图上显示一个半透明模糊效果。若是要用不透明效果,避免用在内容频繁变化的地方。另外,因为内容变化后背景视图和半透明视图必须同时改变,这也会放大功耗。
3. 避免绘制不可见的内容,好比app的内容被其余视图遮挡、被剪切(clipped)或者出画了。
4. 动画尽量用较低的帧率。好比,高帧率在玩游戏时有意义,可是菜单画面可能较低的帧率就够了。只有对用户体验有影响时才使用高帧率。
5. 执行动画时不要修改帧率。好比,你的app帧率是60fps,整个动画就保持这个帧率不要变。
6. 避免同时在屏幕上使用多种帧率。好比,你的游戏人物是60fps,天上的云彩移动又是30fps,不要出现这种情况,就算提升其中某一个的帧率,也要用相同的帧率。
7. 开发游戏时使用推荐的framework。这些framework针对性能和功耗是作过优化的:2D游戏用SpriteKit、3D游戏用SceneKit、画面很是逼真的游戏用Mietal。
全屏播放视频时iOS能够经过高效管理各类资源来优化能耗,可是在视频上下额外添加图层会影响功耗优化效果。app尽可能不要在全屏视频上添加额外的图层(即便是隐藏的图层)。若是用户有须要,能够经过好比单击这样的方式来显示播放控制之类的UI,不须要了之后应该把这些图层移除掉。
优化定位和动做(Motion)
错误使用定位会阻碍设备进入睡眠模式,让定位硬件部分持续通电而消耗电池电量,这会使用户体验变的不好,下面来看一下如何针对功耗优化定位服务。
若是你的app只是须要快速肯定一下用户的位置,最好用CLLocationManager的requestLocation (iOS9引入)方法。定位完成以后会自动让硬件断电。
除了导航,大多数app不须要一直实时更新位置。须要位置服务时开启一下定位,尽可能多隔一些时间再进行下次位置更新,更新完了以后立刻关掉定位。除非用户在移动的交通工具里,不然不频繁地更新位置通常没多大问题。
尽可能下降定位精度。iOS设备默认采用最高精度定位,若是你的app不是确实须要米级的位置信息,不要用最高精度(kCLLocationAccuracyBest)或10米左右的精度(kCLLocationAccuracyNearestTenMeters)。通常来讲Core Location提供的精度比你设置的要好,好比你设置为3千米左右的精度,可能会收到100米左右的精度信息。
若是定位精度一直达不到设置的精度时,中止更新位置,稍后再试。
须要后台更新位置时,尽可能把pausesLocationUpdatesAutomatically设为YES,若是用户不太可能移动的时候系统会自动暂停位置更新。
后台定位时延时更新位置。若是要作一个健身类的软件追踪用户徒步的距离,能够等用户移动一段距离或者过一段时间以后再更新位置,这样可让系统优化能耗。
合理使用访问监控(visit monitoring)。访问监控容许app接收用户频繁或长时间访问的场所的进出通知,好比在家、公司或者去喜欢的咖啡馆。
尽可能不要用significant-change位置服务,优先考虑用region monitoring、 visit monitoring。
用户移动、摇晃、倾斜设备时,会产生动做(motion)事件,这些事件由加速度计、陀螺仪、磁力计等硬件检测。不须要监测设备方向时中止通知。好比用户进入一个只须要竖着显示的画面,及时把方向改变通知关掉。开启动做事件前设置一个比较大的更新间隔。
优化通知
尽可能用本地通知(local notification),若是你的app不依赖外部数据,而是须要基于时间的通知,应该用本地通知,可让设备的网络硬件休息一下。
远程推送有两个级别,一个是当即推送,另外一个是针对功耗优化过的延时推送。若是不是真的须要即时推送,尽可能使用延时推送。
优化蓝牙通讯
1. 没有必要的时候不要扫描蓝牙外设。
2. 扫描外设时通常不要用CBCentralManagerScanOptionAllowDuplicatesKey。
3. 只查找你须要的外设服务。外设可能提供不少服务和特性(characteristic),查找外设的时候能够指定UUID。
4. 不要轮询设备特性值,用通知监测特征值的变化。
5. 特性值再也不提供通知或者再也不须要通讯的时候就断开链接。
Apple Watch
Apple Watch有不少节能的特征,并且watchOS的API也很是高效。可是仍然须要坚持下面的指导方针:
1. 减小iPhone和手表之间的通讯,分批通讯,用NSURLSession的后台会话延迟联网。
2. 去掉没必要要的内容刷新。
3. 尽可能用暗色,亮色会显著增长功耗。除了省电,暗色还可让屏幕边框和显示内容融合得更好
4. 缩小媒体数据大小。若是你的app须要从服务器下载图片,下载适合手表屏幕尺寸的图片,不要下载大图再缩放,这样网络和CPU功耗都更高。
5. 少作工做。若是app须要复杂或者大量的处理任务,考虑将其发送给iPhone处理。
监测功耗
测试或者debug你的app时,注意下列状况:
电池消耗过快
app应该闲置时却活动
响应慢,UI卡顿
主线程执行大量任务
动画使用过多
不透明视图过多
切换应用
内存慢,没有缓存(Memory stalls and cache misses)
内存警告
Lock contention
频繁地切换context
过分使用定时器
频繁绘制屏幕
频繁或者反复执行很小数据的I/O操做
很高的通讯间接功耗,好比传输零散的小数据包和缓冲
设备不休眠
用Xcode测量功耗
开发app的过程当中是诊断能耗最好的时机。在Xcode中选择View > Navigators > Show Debug Navigator,这里提供了不少仪表用于分析功耗。Energy impact能够查看正在运行的app的功耗,如图4。
Cost 和 overhead。蓝色的是CPU执行任务消耗的电量,红色的是执行你的app消耗的其余系统资源电能。
CPU。灰色方块表示你的app正在使用CPU执行任务。
Network。灰色方块表示你的app正在进行网络操做。
Location。灰色方块表示你的app正在使用位置服务。
GPU。灰色方块表示你的app正在使用GPU执行图像相关操做,好比绘图或者播放动画。
Background。灰色方块表示你的app处于后台状态,可是让系统仍然保持唤醒状态。
和用户交互时功耗应该比用户选择一个复杂的操做时低,不交互时不该该有功耗。
使用Instruments以前应该先考虑用Xcode中的仪表检查功耗问题。
用Instruments检测功耗
1. 启动Instruments,选择你的设备和要检测的app,打开Energy Log,如图5。推荐使用无线方式链接设备,这样能够彻底模拟使用电池工做的真实场景。将设备和Mac用数据线链接好,在图5页面按住?选择设备,会出现带有Wireless后缀的设备。
2. 点击Record按钮或者按⌘+R,开始记录。
3. 在设备上正常使用app,这时会记录功耗数据。
4. 点击Stop按钮或按⌘+R,完成记录。
查看记录的数据有没有异常或者能够优化的地方,如图6。
提示:app能耗偶尔比较高不必定是app的问题,可能当时的操做自己就很耗电,好比说执行网络操做的时候使用GPS。你应该关注的是峰值、出乎意料的高功耗区域和其余能够优化的地方。
用iOS设备直接记录功耗
不用有线或无线方式链接Instruments,直接用iOS设备记录功耗能够得到更真实的数据。记录工做几乎不耗电,能够全天候使用,即便设备进入睡眠模式也会持续记录。可是若是设备关机后,数据可能会丢失。
在设备上进入设置 > 开发者 > Logging.
开启功耗记录,如图7。
点击Start Recording按钮。
正常使用设备。
设备记录完成后返回图6所示页面,点击Stop Recording.
在Instruments中选择好设备,进入Energy Log.
选择File > Import Logged Data from Device。
使用其余模板和仪器检测功耗
有不少因素会影响app的功耗,Engergy Log这个模板能够分析一部分因素,你还能够用其余的模板或工具检查app对功耗的影响。
Activity Monitor. 查看CPU、I/O、网络使用。
Core Animation. 测量图像性能和CPU使用量。
GPU Driver. 测量GPU驱动数据。
Location Energy Impact. 测量Core Location对能耗的影响。
Metal System Trace. 经过追踪app、驱动、GPU的数据,检测iOS Metal应用的性能。
Network. 分析TCP/IP 和UDP/IP 链接。
Time Profiler. 该工具检测app正在运行的线程,隔一段时间采样一次。每一个采样都有完整的调用栈(backtrace),你能够找出你的代码中哪里耗费了大量时间。
自定义模板。上面的模板或仪器能够分析app的多个方面。若是你想查看特定的几个方面,能够向Instruments中添加单个的仪器。若是之后可能还要用相同的分析类型,能够把你配置的工具保存成模板。
测试性能
app的性能降低会致使功耗增长,能够用Xcode中的XCTest框架测试你的代码。代码会在性能测试的block中连续运行10次,并给出运行平均时间的标准差。