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
操作步骤
- 手机设置 → “开发者” → “Logging” → 勾选 “Energy” → “Start Recording”
- 运行 App 3-5 分钟 → 返回设置停止录制
- 连接 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 |
来源
- 原文链接:iOS 耗电量检测与优化 - 简书