性能是客户端永远绕不开的话题,一起来康康今年的WWDC提供了哪些有关性能提升的建议吧~
(温馨提示:本片内容来源自WWDC21:Ultimate application performance survival guide)
想了解更多WWDC2021内容的小伙伴,可以阅读我以下文章,欢迎多多交流和指正
使用的五种工具
- Xcode Organizer
- MetricKit
- Instruments
- XCTest
- App Store Connect API
参考的八个性能指标
电量
启动时间
超时响应率(Hang rate)
APP无法响应用户的输入或者行为超过250ms,即记作一个hang
内存
磁盘写入
滚动卡顿
APP终止
MXSignposts
电量(battery usage)
优化电池使用需要关注的几点:
- CPU
- 网络
- 定位
- 音频
- 蓝牙
- GPU
其中CPU、网络、定位是电量消耗大户
使用Xcode工具查看Debug期间的电量损耗情况
- 查看CPU超过20%的阶段(CPU High Utilization)
- 查看CPU从闲置被唤醒的阶段(CPU Wake Overhead)
使用Instrument中的Time Profile工具查看该阶段更详细的信息
(比如使用Location Energy Model确保应用如预期中正确地使用定位功能)
使用MetricKit收集用户的性能数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23// 创建遵守`MXMetricManagerSubscriber`的协议的类AppMetrics
class AppMetrics: MXMetricManagerSubscriber {
init() {
// 初始化时将AppMetrics加入到`MXMetricManager`单例中
let shared = MXMetricManager.shared
shared.add(self)
}
deinit {
// 销毁时进行移除
let shared = MXMetricManager.shared
shared.remove(self)
}
// 处理每日的metrics
func didReceive(_ payloads: [MXMetricPayload]) {
}
// 处理diagnostics
func didReceive(_ payloads: [MXDiagnositcPayload]) {
}
}
使用Xcode Organizer查看线上性能数据
Xcode Organizer对MetrixKit收集到的数据进行了聚合,忽略了单一用户的详细数据,展现的是整体的趋势;
而使用MetricKit可以更具针对性的对某一用户在一段时间内的性能表现进行分析。
- 查看用户的电量使用情况
Regressions
Regressions是Xcode 13新增的模块,它将各个版本的性能指标中发生劣化的情况单独拎出来展示,让开发者更清晰的看到哪些性能指标亟待优化。
查看问题发生时对应的代码
超时响应率和滚动卡顿(Hang rate & Scrolling)
超时响应
长时间无法响应是导致用户强退应用的重要原因
滚动卡顿
当在下一次屏幕刷新时,新的内容还未ready就会出现卡顿
Hang rate & Scrollings是表明APP没有及时响应的两个指标,一旦发生会严重影响用户体验,甚至让用户在使用应用时产生挫败感,从而降低用户的使用APP的意愿。
使用Xcode Organizer查看线上的卡顿情况
- Hang rate
- Scrolling
使用Instrument进行分析
Thread State Trace
可以查看线程被阻塞的详细情况
System Call Trace
可以查看系统函数调用的时机和时长
使用XCTest进行性能测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18func testScrollingAnimationPerformance() throws {
app.launch()
app.staticTexts["Meal Planner"].tap()
let foodCollection = app.collectionViews.firstMatch
// `measure`函数默认重复5次,可以通过option设置手动停止
let measureOptions = XCTMeasureOptions()
measureOptions.invocationOptions = [.manuallyStop]
// 开始measure
measure(metrics: [XCTOSSignpostMetric.scrollDecelerationMetric],
option: measureOptions) {
// 滑动
foodCollection.swipeUP(velocity: .fast)
// 停止measure
stopMeasuring()
// 重置状态
foodCollection.swipeDown(velocity: .fast)
}
}使用MetricKit收集线上数据
在iOS 14中,MetricKit会收集用户使用过程中发生的问题,然后每24小时集中上报一次。
在iOS 15和MacOS 12中,MetricKit仍是每天上报一次,但会在
addSubscriber
后,并且立刻进行回调
iOS 15中MetricKit新增动画性能检测的API,能够记录动画期间详细的性能数据和卡顿情况
1
2
3
4
5
6
7
8
9
10
11
12func startAnimating() {
// 标记动画开始执行
mxSignpostAnimaitionIntervalBegin(
log: MXMetricManager.makeLogHandle(category: "animation"_telemetry),
name: "custom_animation")
)
}
func animationDidComplete() {
// 标记动画结束
mxSignpost(OSSignpostType.end, log: MXMetricManager.makeLogHandle(category: "animation_telemetry"), name: "custom_animation")
}1
2
> 注:MXSignpost是MetricKit中封装的API,可以用来监控关键代码的运行情况磁盘写入
使用Instrument中的File Activity查看磁盘写入情况
优化建议:
对于频繁写入的case,推荐使用Core Data
避免快速创建和删除文件
使用XCTest进行性能测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16func testSaveMeal() {
let app = XCUIApplication()
let options = XCTMeasureOptions()
options.invocationOptions = [.manullyStart]
// 检测下面代码运行时的磁盘写入情况
measure(metrics: [XCTStorageMetric(application: app)], options: options) {
app.launch()
startMeasuring()
let firstCell = app.cells.firstMatch
firstCell.buttons["Save meal"].firstMatch.tap()
let savedButton = firstCell.buttons["Saved"].firshMatch
XCTAssertTure(savedButton.waitForExistence(timeout: 2))
}
}使用Xcode Organizer查看线上磁盘写入情况
- 查看在Disk Writes报告中可以查看24小时内写入量超过1GB的case
- 在Xcode 13中,还可以得到一些优化建议
使用MetricKit收集用户的磁盘写入情况
1
2
3
4
5
6
7
8
9
10
11
12
13// 标记开始磁盘写入
func syncAllContentsToDB() {
mxSignpost(OSSignpostType.begin,
log:MXMetricManager.makeLogHandle(categroy: "diskWrite_telemetry"),
name: "custom_diskWrites")
// sync contents to database
// 标记磁盘写入结束
mxSignpost(OSSignpostType.end,
log:MXMetricManager.makeLogHandle(category: "diskWrite_telemetry"),
name: "custom_diskWrites")
}
启动时间
使用Xcode Organizer查看线上启动数据
- 查看因启动超时导致的程序终止
使用Instrument中的App Launch工具进一步分析
Memory
使用Xcode Organizer查看线上内存使用情况
使用Instrument中的Leak、Allocations和VM Tracker三个模板
- Leak检测内存泄漏
- Allocations分析内存的生命周期
- VM Tracker展示虚拟内存空间的使用情况
使用MetricKit收集线上数据
1
2
3
4
5
6
7
8
9
10
11func saveAppAssets() {
mxSignpost(OSSignpostType.begin,
log: MXMetricManager.makeLogHandle(category: "memory_telemetry"),
name: "custom_memory")
// save app metadata
mxSignpost(OSSignpostType.end,
log: MXMetricManger.makeLogHandle(category: "memory_telemetry"),
name: "custom_memory")
}
更多有关电量优化的Session:
Improving battery life and performance WWDC19
Analyze HTTP traffic in Instruments WWDC 21
更多Hang优化的Session:
Understand and Eliminate Hangs from you app WWDC21
更多滚动优化的Session:
Explore UI animation hitches and the render loop WWDC20
Eliminate animation hitches with XCTest WWDC20
更多磁盘写入优化的Session:
Diagnose power and performance regressions in your app WWDC21
更多启动优化的Session:
Why is my app getting killed WWDC20
更多内存优化的Session:
Detect and diagnose memory issues
更多关于性能工具的Session:
Diagnose performance issues with Xcode Organizer WWDC20
What’s new in MetricKit WWDC20