iOS 耗电量检测与优化 封面
iOS 性能

iOS 耗电量检测与优化

耗电优化不能只盯着某一段代码。先用 Energy Impact 和 Instruments 找到高耗电区,再分别检查刷新、网络、定位、后台任务和图片处理,效果更容易验证。

最后编辑时间:2017年12月6日

简介

这里介绍如何检测和优化 iOS 应用的耗电量,帮助开发者提升应用性能和用户体验。


一、耗电量检测

1. 系统设置查看

进入手机 “设置” → “电池”,可以直观查看各应用的耗电情况。

2. Xcode Energy Impact 工具

使用真机运行项目,通过 Xcode 的 Debug Navigator(Command + 6)点击 “Energy Impact” 查看。

能耗指标说明

颜色 含义
🟦 蓝色 合理
🟨 黄色 较耗电
🟥 红色 轻度使用即严重耗电

指标详解

  • Utilization:瞬时耗电情况
  • Average:平均耗电情况
  • Energy Impact:
    • Cost(蓝色):运行代码所需电量
    • Overhead(红色):系统资源开销(如 CPU 唤起、网络模块、定位等)

五大耗电因素

因素 说明 优化建议
CPU 使用率超 20% 会快速耗电 高效使用并快速响应用户输入
Network 频繁唤起无线电模块 分批进行网络请求
Location 精确定位 按需使用
GPU 过度使用导致交互卡顿 避免过度使用
Background 后台操作 进入后台后立即减少操作,使用延迟 API

3. Instruments 的 Energy Log

操作步骤

  1. 手机设置 → “开发者” → “Logging” → 勾选 “Energy” → “Start Recording”
  2. 运行 App 3-5 分钟 → 返回设置停止录制
  3. 连接 Xcode → 打开 Instruments 的 “Energy Log” → 导入设备日志

日志分析

  • Energy Usage Level(0-20):值越大越耗电
  • CPU Activity:显示 CPU 各类活动详情

二、耗电量优化

1. 代码层面优化

日期格式化优化

缓存常用的 NSDateFormatter 格式,避免重复创建。

static NSDateFormatter *cachedDateFormatter = nil;

+ (NSDateFormatter *)cachedDateFormatter {
    if (!cachedDateFormatter) {
        cachedDateFormatter = [[NSDateFormatter alloc] init];
        [cachedDateFormatter setDateFormat:@"YYYY-MM-dd HH:mm:ss"];
    }
    return cachedDateFormatter;
}

减少界面刷新

  • 优先刷新单个 Cell,避免全表 reloadData
  • 使用 reloadRowsAtIndexPaths 或 reloadSections

选择合适的集合类型

类型 特点
NSArray 按索引查找快,增删慢
NSDictionary 按键查找快
NSSet 无序,增删查均快

避免实时圆角计算

  • 预渲染圆角图片替代 maskToBounds/clipToBounds
  • 使用 CALayer 的 cornerRadius 属性
view.layer.cornerRadius = 8;
view.layer.masksToBounds = YES;

懒加载与重用

  • 按需创建子视图
  • 复用类似 UITableView 的机制

图片处理

  • 图片尺寸与 UIImageView 匹配,避免缩放开销
  • 预渲染图片或使用 CALayer/CoreGraphics 绘制
  • 使用 SDWebImage 等图片加载库缓存图片
// 优化:按需加载合适尺寸的图片
UIImage *resizedImage = [originalImage resizableImageWithCapInsets:edgeInsets resizingMode:UIImageResizingModeStretch];

缓存策略

  • 缓存网络响应(如图片)
  • 缓存复杂计算结果(如行高)
// 示例:缓存行高计算结果
NSMutableDictionary *heightCache = @{};
CGFloat rowHeight = [heightCache[@(indexPath.row)] floatValue];
if (rowHeight == 0) {
    rowHeight = [self calculateHeightForRowAtIndexPath:indexPath];
    heightCache[@(indexPath.row)] = @(rowHeight);
}

减少透明度

  • 避免不必要的透明层混合计算
  • 设置 opaque = YES 减少混合开销
view.opaque = YES;
view.backgroundColor = [UIColor whiteColor];

使用 ARC

  • 合理管理内存
  • 重写 dealloc 释放资源
- (void)dealloc {
    // 清理资源
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

减少 XIB/Storyboard 使用

  • 优先用代码布局
  • XIB 加载开销较大

2. CPU 层面优化

Timer 间隔

  • 按需设置,不宜过短
  • 避免高频触发
// 优化:合理的 Timer 间隔
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
    // 执行任务
}];

线程管理

  • 避免阻塞主线程
  • 控制线程数量,避免创建过多线程
  • 使用 NSOperationQueue 或 GCD 管理并发
// 示例:后台队列处理耗时任务
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // 耗时操作
    dispatch_async(dispatch_get_main_queue(), ^{
        // 更新 UI
    });
});

算法优化

  • 减少循环次数
  • 使用高效的数据结构和算法
  • 避免嵌套循环

定位/蓝牙

  • 按需启用
  • 及时关闭或降低频率
// 示例:按需开启定位
[locationManager startUpdatingLocation];
// 使用完毕后及时关闭
[locationManager stopUpdatingLocation];

三、最佳实践

1. 使用后台任务 API

// 使用 beginBackgroundTaskWithExpirationHandler 确保后台任务完成
__block UIBackgroundTaskIdentifier task = [application beginBackgroundTaskWithExpirationHandler:^{
    [application endBackgroundTask:task];
    task = UIBackgroundTaskInvalid;
}];

2. 使用 NSURLSession 批量网络请求

NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
config.discretionary = YES; // 允许系统优化网络请求时机

3. 使用 Core Motion 的低功耗模式

CMMotionActivityManager *activityManager = [[CMMotionActivityManager alloc] init];
// 使用低功耗的活动识别
[activityManager startActivityUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMMotionActivity *activity) {
    // 处理活动数据
}];

四、总结

优化方向 关键点
CPU 降低使用率,避免长时间运行
网络 批量请求,减少唤醒
定位 按需使用,降低频率
GPU 避免过度渲染
后台 快速减少操作,使用延迟 API

来源