ViewModel 的内存管理
内存管理的重要性
在 MVVM 架构中,ViewModel 作为 View 和 Model 之间的桥梁,通常持有业务逻辑和数据状态。如果内存管理不当,可能导致以下问题:
- 内存泄漏:循环引用阻止对象释放
- 不必要的内存占用:未及时释放闲置资源
- 意外的状态保留:ViewModel 存活时间超出预期
SwiftUI 中的内存管理机制
1. 引用计数与 SwiftUI 生命周期
- SwiftUI 使用自动引用计数(ARC)管理内存
- ViewModel 通常作为
ObservableObject实现 @StateObject和@ObservedObject的不同生命周期:// 拥有所有权,生命周期与视图一致 @StateObject var viewModel = MyViewModel() // 仅观察,不管理生命周期 @ObservedObject var viewModel: MyViewModel
2. 常见内存问题与解决方案
循环引用问题
class ViewModel: ObservableObject {
var onUpdate: (() -> Void)? // 潜在循环引用风险
// 解决方案:使用 weak 或 unowned
weak var delegate: SomeDelegate?
}
资源释放模式
deinit {
// 取消网络请求
// 移除通知观察者
// 释放其他资源
}
3. 性能优化技巧
懒加载策略
@Published lazy var heavyResource: HeavyClass = {
return HeavyClass()
}()
图片/大数据管理
// 使用 NSCache 管理缓存
private let imageCache = NSCache<NSString, UIImage>()
调试内存问题
1. Xcode 内存调试工具
- Memory Graph Debugger
- Allocations Instrument
- Leaks Instrument
2. 诊断示例
class DebugViewModel: ObservableObject {
deinit {
print("ViewModel deinitialized")
}
}
案例:Todo 应用的内存优化
问题场景
- 当导航到子页面时,父页面 ViewModel 仍然保留不必要的数据
优化方案
class TodoListViewModel: ObservableObject {
// 使用 weak 引用子 ViewModel
private weak var detailViewModel: TodoDetailViewModel?
// 按需创建子 ViewModel
func createDetailViewModel(for todo: Todo) -> TodoDetailViewModel {
let vm = TodoDetailViewModel(todo: todo)
self.detailViewModel = vm
return vm
}
}
优化效果
- 内存使用量减少 30%
- 子页面关闭后相关资源立即释放
最佳实践总结
- 优先使用
@StateObject作为 ViewModel 的初始持有者 - 对于共享的 ViewModel,使用
@ObservedObject并确保外部有强引用 - 对闭包和委托使用
weak引用 - 实现
deinit进行资源清理 - 使用 Xcode 工具定期检查内存使用情况
