案例:优化 Todo 应用的性能
问题背景
在 Todo 应用的开发过程中,随着数据量增加和功能扩展,可能会出现以下性能问题:
- 列表滚动卡顿
- 频繁的视图重绘
- 内存占用过高
- 数据更新延迟
优化策略
1. 视图层级优化
// 优化前:嵌套过多的容器
VStack {
ForEach(todos) { todo in
HStack {
VStack(alignment: .leading) {
Text(todo.title)
Text(todo.detail)
}
Spacer()
Image(systemName: "checkmark")
}
.padding()
}
}
// 优化后:扁平化视图结构
List(todos) { todo in
TodoRow(todo: todo) // 提取为独立视图组件
}
2. 列表性能优化
// 使用 identifiable 数据避免不必要的刷新
struct Todo: Identifiable {
let id = UUID()
var title: String
var detail: String
}
// 对于复杂列表项实现 Equatable 协议
extension Todo: Equatable {
static func == (lhs: Todo, rhs: Todo) -> Bool {
lhs.id == rhs.id &&
lhs.title == rhs.title &&
lhs.detail == rhs.detail
}
}
3. 状态管理优化
// 使用 @StateObject 替代 @ObservedObject 避免重复创建
class TodoViewModel: ObservableObject {
@Published var todos: [Todo] = []
// 使用 debounce 减少频繁更新
private var cancellables = Set<AnyCancellable>()
init() {
$todos
.debounce(for: 0.3, scheduler: RunLoop.main)
.sink { _ in
self.objectWillChange.send()
}
.store(in: &cancellables)
}
}
4. 内存优化
// 使用 lazy 加载大资源
struct TodoDetailView: View {
@State private var image: UIImage?
let todo: Todo
var body: some View {
VStack {
if let image = image {
Image(uiImage: image)
.resizable()
.scaledToFit()
} else {
ProgressView()
.task {
image = await loadLargeImage()
}
}
}
}
}
性能测试与验证
1. 使用 Instruments 分析
- Time Profiler: 检测CPU使用情况
- Memory Graph: 检查内存泄漏
- SwiftUI Body 调用次数: 验证不必要的视图刷新
2. 性能基准测试
func testPerformance() {
measure {
let viewModel = TodoViewModel()
viewModel.todos = (1...1000).map {
Todo(title: "Task \($0)", detail: "Detail \($0)")
}
let view = TodoListView(viewModel: viewModel)
let _ = view.body
}
}
优化结果对比
| 指标 | 优化前 | 优化后 |
|---|---|---|
| 列表滚动FPS | 40 fps | 60 fps |
| 内存占用 | 120 MB | 80 MB |
| 数据加载时间 | 1.2s | 0.4s |
| 视图刷新次数 | 200次/操作 | 1次/操作 |
持续优化建议
- 对于超长列表考虑实现分页加载
- 复杂计算移至后台线程
- 使用
@ViewBuilder构建条件视图 - 定期使用 Xcode 的 Canvas 预览检查性能
