iOS在优化电量时主要基于以下几个方面:
1.减少任务量,并对任务区分优先级。
2.减少网络请求,并推迟不重要的网络请求
3.高效的使用图形,动画和音视频。
4.优化位置服务和动作服务(GPS,陀螺仪)
5.优化通知服务(本地通知和远程通知)
6.减少外设交互(主要为蓝牙设备)
一、首先介绍如何减少任务量和对任务进行优先级划分
1.对于需要在后台执行的任务,应在后台任务完成时通知系统,使CPU更快的进入空闲状态。iOS允许用户在applicationDidEnterBackground方法中执行几秒的任务,但是如果你需要额外的时间来执行后台任务,那么需要像系统申请额外的事件来执行。
// 申请额外的后台执行时间
UIBackgroundTaskIdentifier bgTaskID = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
// 当后台申请的时间用完时,系统会调用这个block的代码
}];
//在这里开始执行后台任务
// 执行完任务之后要通知系统任务完成了,以避免不必要的电量消耗
[[UIApplication sharedApplication] endBackgroundTask:bgTaskID];
2.对异步任务的优先级进行划分。因为系统的资源是有限的,手机的许多进程和任务会竞争使用资源,包括CPU,内存,网络等,为了能够高效,快速的对任务作出反应,系统需要根据任务优先级来合理的安排何时执行任务。系统使用QoS(Quality of Service Class)信息来决定调度的优先级。
以下为区分Qos的标准
QoS等级 | 工作类型和QoS级别 | 要完成的工作持续时间 |
---|---|---|
User-interfactive | 与用户交互的工作,例如在主线程上操作,刷新用户界面或执行动画。如果工作没有快速完成,用户界面可能冻结。重点关注响应能力和性能。 | 工作几乎是即时的。 |
User-initiated | 用户已启动并需要立即生成的结果,例如打开已保存的文档或在用户单击用户界面中的某些内容时执行的操作。需要这项工作才能继续用户交互。重点关注响应能力和性能。 | 工作几乎是即时的,例如几秒钟或更短时间。 |
Utility | 可能需要一些时间才能完成并且不需要立即结果的工作,例如下载或导入数据。实用程序任务通常具有用户可见的进度条。着重于在响应性,性能和能效之间取得平衡。 | 工作需要几秒钟到几分钟。 |
Backgroud | 在后台运行并且对用户不可见的工作,例如索引,同步和备份。重点关注能源效率。 | 工作需要很长时间,例如几分钟或几小时。 |
通常来说,当用户不再与App交互时,90%的时间都用来执行QoS级别为Utility或者更低级别的任务。当iPhone在低电量模式下,系统会停止后台任务及discretionary任务。
除了上面最主要的QoS级别以外,还有两个QoS级别
QoS等级 | 描述 |
---|---|
Default | 此QoS的优先级落在user-initiated和utility之间。此QoS不推荐开发人员用于对工作进行分类。未分配QoS信息的工作被视为Default,GCD全局队列在此级别运行。 |
Unspecified | 这表示缺少QoS信息,并提示系统应推断出环境QoS。如果线程使用可能选择脱离QoS的线程的旧API,则线程可能具有未指定的QoS。 |
对NSOperationQueue设置QoS
对Dispatch Queue和Blocks设置Qos
NSOperation *myOperation = [[NSOperation alloc] init];
myOperation.qualityOfService = NSQualityOfServiceUtility;
dispatch_queue_attr_t qosAttribute = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_CONCURRENT, QOS_CLASS_UTILITY, 0);
dispatch_queue_t myQueue = dispatch_queue_create("com.YourApp.YourQueue", qosAttribute);
Global queue | Corresponding QoS class |
---|---|
Main thread | User-interactive |
DISPATCH_QUEUE_PRIORITY_HIGH | User-initiated |
DISPATCH_QUEUE_PRIORITY_DEFAULT | Default |
DISPATCH_QUEUE_PRIORITY_LOW | Utility |
DISPATCH_QUEUE_PRIORITY_BACKGROUND | Background |
3.减少Timer的使用,高效的使用定时器
使用Timer的高级API 包括CFRunLoopTimerCreate,NSTimer
,performSelector:withObject:afterDelay:
使用Timer的低级API包括sleep
, usleep
, nanosleep
, pthread_cond_timedwait
, select
, poll
, kevent
, dispatch_after,
dispatch_semaphore_wait。使用Timer的时候,应遵守以下原则:(1)设置合适的超时时间
while (YES) {
dispatch_time_t timeout = DISPATCH_TIME_FOREVER;
long semaphoreReturnValue = dispatch_semaphore_wait(mySemaphore, timeout);
if (havePendingWork) {
[self doPendingWork];
}
}
(2)在不使用的时候将Timer置为无效,
NSTimer *myTimer = [[NSTimer alloc] initWithFireDate:date
interval:1.0
target:self
selector:@selector(timerFired:)
userInfo:nil
repeats:YES];
/* Do work until the timer is no longer needed */
[myTimer invalidate]; /* Recommended */
(3)设置Timer触发的容错。
[myTimer setTolerace:0.3]; 10%的容错
[[NSRunLoop currentRunLoop] addTimer:myTimer forMode:NSDefaultRunLoopMode];
4.减少I/0操作
系统会在低电量模式下执行以下设置来减少电量消耗
-
最小化数据写入。仅在内容发生更改时写入文件,并尽可能将更改聚合为单个写入。如果只有几个字节发生了变化,请避免写出整个文件。如果经常更改大部分文件,请考虑使用数据库来存储数据。
-
避免过于频繁地访问内存。如果您的应用程序保存状态信息,请仅在状态信息更改时才这样做。尽可能批量更改,以避免频繁写入小的更改。
-
尽可能顺序读写数据。在文件中跳转需要额外的时间来寻找新位置。
-
尽可能从文件中读取和写入更大的数据块,请记住,一次读取太多数据可能会导致其他问题。例如,读取32 MB文件的全部内容可能会在操作完成之前触发对这些内容的分页。
-
要读取或写入大量数据,请考虑使用
dispatch_io
,它提供了一个基于GCD的异步API来执行文件I / O. 使用dispatch_io
允许您在较高级别指定数据需求,以便系统可以优化您的访问。参见Grand Central Dispatch(GCD)参考。 -
如果您的数据由随机访问的结构化内容组成,则将其存储在数据库中并使用例如SQLite或Core Data访问它。如果您操作的数据量可能增长到几兆字节,则使用数据库尤为重要。请参阅SQLite软件库和核心数据编程指南。
-
了解系统如何缓存文件数据并了解如何优化这些缓存的使用。除非您计划多次引用数据,否则请避免自己缓存数据。见该系统具有它自己的文件缓存机制的文件系统编程指南。
-
降低CPU和GPU性能
-
暂停自行决定和后台活动,包括网络
-
降低屏幕亮度
-
减少自动锁定设备的超时时间
-
禁用邮件提取
-
禁用动作效果
-
禁用动画壁纸
如果希望对电池管理状态的变化进行操作,那么需要注册通知
查询电源状态
[[NSNotificationCenter defaultCenter] addObserver:self
selector: @selector(yourMethodName:)
name: NSProcessInfoPowerStateDidChangeNotification
object: nil];
if ([[NSProcessInfo processInfo] isLowPowerModeEnabled]) {
// Low Power Mode is enabled. Start reducing activity to conserve energy.
} else {
// Low Power Mode is not enabled.
};
-