简而言之--使用ViewModel("MyView"/"MyViewModel")构建自定义SwiftUI视图时,如下所示:
struct ContentView: View {
var body: some View {
MyView(viewModel: MyViewModel())
}
}
为什么会这样:
struct MyView: View {
@StateObject var viewModel: MyViewModel
var body: some View {
Text("Hello world!")
}
}
与此不同:
struct MyView: View {
@StateObject var viewModel: MyViewModel
init(viewModel: MyViewModel) {
self._viewModel = StateObject(wrappedValue: viewModel)
}
var body: some View {
Text("Hello world!")
}
}
在调试时,第二个选项似乎会在SwiftUI每次重新构建MyView
时创建MyViewModel
的新实例.但在第一个选项中,StateObject包装器似乎完成了它的工作,并确保只为MyView
的所有重建创建一个MyViewModel
的实例.
是否有一些额外的SwiftUI魔力应用于使用视图的默认成员式初始化器与自定义初始化器?也许是通过ViewBuilder?
下面是一个简单的示例应用程序MyApp.swft,它可以查看这种行为的实际情况.
//
// MyApp.swift
//
import SwiftUI
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
struct ContentView: View {
@AppStorage("redBackground") private var redBackground: Bool = false
var body: some View {
ZStack {
// Flipping "redBackground" will cause a reconstruction of the view hierarchy
if redBackground {
Color.red
} else {
Color.green
}
MyView(viewModel: MyViewModel())
}
}
}
final class MyViewModel: ObservableObject {
init() {
print("MyViewModel.init")
}
}
struct MyView: View {
@StateObject var viewModel: MyViewModel
@AppStorage("redBackground") private var redBackground: Bool = false
// WARNING: Uncommenting this causes the view model to be recreated every reconstruction of the view!
// init(viewModel: MyViewModel) {
// self._viewModel = StateObject(wrappedValue: viewModel)
// }
var body: some View {
VStack {
Button("Toggle background") {
redBackground = !redBackground
}
}
}
}