最近看了斯坦福大学 2020 春季的 SwiftUI 课程,总结一下 SwiftUI 是如何支持 MVVM 设计模式的。
介绍
MVVM(Model-View-ViewModel)并非一种框架,而是一种架构模式,一种思想,一种组织和管理代码的方法。它本质上就是 MVC(Model-View- Controller)的一种改进版。
原则
在 MVVM 架构中 View 和 Model 不能直接通信,必须通过 ViewModel。ViewModel 是 MVVM 的核心,它通常要实现一个观察者,当 Model 数据发生变化时 ViewModel 能够监听并通知到对应的 View 做 UI 更新,反之当用户操作 View 时 ViewModel 也能获取到数据的变化并通知 Model 数据做出对应的更新操作。这就是 MVVM 中数据的双向绑定。
- Model—>View:将数据转化成页面。
- View—>Model:将页面转化成数据。
SwiftUI中的MVVM
SwiftUI + Combine 原生就是 MVVM 架构,且能很容易地支持数据的双向绑定。
Model—>View
View—>Model
View<—>Model
结构体与类
class 的最后一条,ViewModel 总是 class 而不是 struct。
案例
- Model
struct Country: Identifiable {
let id: UUID = UUID()
let name: String
}
- View
struct ContentView: View {
@ObservedObject var viewModel: ViewModel = ViewModel()
var body: some View {
List{
ForEach(viewModel.countries) { country in
Text(country.name)
}
.onDelete{ index in
self.viewModel.removeCountry(index.first!)
}
}.onAppear {
self.viewModel.loadCountries()
}
}
}
- ViewModel
class ViewModel: ObservableObject {
@Published private(set) var countries: [Country] = []
func loadCountries() {
self.countries = [Country(name: "中国"), Country(name: "美国"), Country(name: "韩国"), Country(name: "德国"), Country(name: "法国"), Country(name: "英国")]
}
func removeCountry(_ index: Int) {
self.countries.remove(at: index)
}
}
Model—>View
- List(View)显示时
onAppear
调用,紧接着调用 ViewModel 中的loadCountries()
。 - ViewModel 中的
loadCountries()
构造/获取数据并转化为 Model。 - ViewModel 通过
@Published
修饰的属性发出数据变化通知。 - View 中的
@ObservedObject
收到通知后驱动 UI 更新。
View—>Model
- List(View)侧滑时,进行删除操作,调用 ViewModel 中的
removeCountry()
。 - ViewModel 中的
removeCountry()
操作数据 Model。 - ViewModel 通过
@Published
修饰的属性发出数据变化通知。 - View 中的
@ObservedObject
收到通知后驱动 UI 更新。