首先,让我们弄清楚"重新渲染"是什么意思.如果您的意思是"创建一个全新的视图",那么只有在视图的identity更改时才会发生这种情况.如果您的视图标识不依赖于ModalObservable
,那么您如何更改ModelObservable
就无关紧要了.这可以通过实验检测到onAppear
.
如果你的意思是"更新一个现有的视图",那么这取决于视图的dependencies.SwiftUI根据视图和视图使用的状态/绑定/环境等创建依赖关系图,并在任何依赖关系发生变化时更新视图.这可以通过让body
产生一个副作用来实验性地检测到(尽管在第一次创建视图时也会调用body
).
以下是一些代码,您可以使用它们进行实验:
struct ContentView: View {
@State var model = ModalObservable()
var body: some View {
let _ = print("ContentView updates")
UpdateDetector(observable: model)
Button("Change Open") {
model.changeOpen()
}
Button("Change View") {
model.changeView()
}
}
}
struct UpdateDetector: View {
let observable: ModalObservable
var body: some View {
let _ = print("UpdateDetector updates")
Text(observable.state.open ? "Open" : "Close")
}
}
@Observable class ModalObservable {
var state = ModelState()
func changeView() {
self.state.view = UUID().uuidString
}
func changeOpen() {
self.state.open.toggle()
}
}
struct ModelState {
var view = "Foo"
var open = false
}
在这里,SwiftUI已经确定UpdateDetector
依赖于observable.state
,所以每当它观察到observable.state
中的变化时,即当按下任何一个按钮时,它都会更新.另一方面,ContentView
不更新,因为它不依赖于任何可观察到的属性.
请注意,observable.state.open
和observable.state.view
不能算作两个单独的可观察属性,因为@Observable
宏只将@ObservationTracked
与state
相加.
这是另一个例子,这一次是Binding
.
struct ContentView: View {
@State var model = ModalObservable()
var body: some View {
let _ = print("ContentView updates")
UpdateDetector(open: $model.state.open)
Button("Change Open") {
model.changeOpen()
}
Button("Change View") {
model.changeView()
}
}
}
struct UpdateDetector: View {
@Binding var open: Bool
var body: some View {
let _ = print("UpdateDetector updates")
Text(open ? "Open" : "Close")
}
}
在这里,UpdateDetector
只依赖于open
绑定,所以按"更改视图"不会更新它,但按"更改打开"会更新它.另一方面,ContentView
现在也依赖于open
绑定,因为绑定是双向的.按下"更改打开"也会更新ContentView
.
如果你do希望observable.state.open
和observable.state.view
被分开跟踪,你可以把ModelState
也变成一个@Observable
类,尽管这也改变了语义.
@Observable
class ModelState {
var view = "Foo"
var open = false
}