TestView3可以显示2张纸:TestView4和TestView5。 TestView4具有@State值,该值从TestView3初始化。 TestView5也具有@ObservedObject值,该值也可以从TestView3初始化。
当我切换全局值(global.on)时,它将更新TestView3,然后导致TestView4或TestView5 init()。
Q1。更新TestView3时如何避免在TestView4或TestView5中调用init()?如何完全隔离带有图纸的视图与视图?否则视图中的任何更新都会影响工作表,这太糟糕了。
第二季度。 TestView4或TestView5中init()的行为不同。 TestView4中的本地@State在init()中不会更改。但是本地@ObservedObject将在init()中更改。为什么?好奇怪如何使@ObservedObject不会由于TestView3更新而在init()中更改?
您可以测试以下代码,跟踪日志很奇怪。
class Global: ObservableObject {
static let shared = Global()
@Published var on: Bool = false
}
class Local: ObservableObject {
@Published var on: Bool = false
init(_ on: Bool) {
self.on = on
}
}
struct TestView3: View {
@ObservedObject var global = Global.shared
@State private var sheetShowing = false
@State private var sheetShowingId = 4
var body: some View {
print("test view3 body, glabel on = \(global.on)"); return
VStack {
Text("Global").foregroundColor(global.on ? .red : .gray).onTapGesture {
self.global.on.toggle()
}.padding()
Button(action: {
self.sheetShowing = true
self.sheetShowingId = 4
print("test view3, will show test view4")
}) { Text("Show TestView4") }.padding()
Button(action: {
self.sheetShowing = true
self.sheetShowingId = 5
print("test view3, will show test view5")
}) { Text("Show TestView5") }.padding()
}.sheet(isPresented: $sheetShowing) {
if self.sheetShowingId == 4 {
TestView4(on: self.global.on)
} else {
TestView5(on: self.global.on)
}
}
}
}
struct TestView4: View {
@State private var on: Bool
init(on: Bool) {
self._on = State(initialValue: on)
print("test view4 init, glabel on = \(Global.shared.on), local on = \(self.on)")
}
var body: some View {
print("test view4 body, glabel on = \(Global.shared.on), local on = \(on)"); return
VStack {
Text("TestView4").padding()
Text("Local").foregroundColor(on ? .red : .gray).onTapGesture {
self.on.toggle()
print("test view4, local toggle")
}.padding()
Text("Global").foregroundColor(Global.shared.on ? .red : .gray).onTapGesture {
Global.shared.on.toggle()
print("test view4, global toggle")
}.padding()
}
}
}
struct TestView5: View {
@ObservedObject var local: Local
init(on: Bool) {
self._local = ObservedObject(initialValue: Local(on))
print("test view5 init, glabel on = \(Global.shared.on), local on = \(self.local.on)")
}
var body: some View {
print("test view5 body, glabel on = \(Global.shared.on), local on = \(local.on)"); return
VStack {
Text("TestView5").padding()
Text("Local").foregroundColor(local.on ? .red : .gray).onTapGesture {
self.local.on.toggle()
print("test view5, local toggle")
}.padding()
Text("Global").foregroundColor(Global.shared.on ? .red : .gray).onTapGesture {
Global.shared.on.toggle()
print("test view5, global toggle")
}.padding()
}
}
}
答案 0 :(得分:0)
第一季度:您无法避免。为什么?每次包装在State或ObservedObject中的TestView3属性的值更改时,它都会重新计算其主体。即使TestView3或TestView4不受此值的影响,声明的这一部分
if self.sheetShowingId == 4 {
TestView4(on: self.global.on)
} else {
TestView5(on: self.global.on)
}
代表一个视图,其主体必须重新评估。
Q2:这没有简单的答案,只是因为我们对彼此的实现细节不太了解。至少我建议您不要依赖您的调查:-)。大约,很容易看到您在TestView5.init中创建了模型Local()的新(本地副本)。
init(on: Bool) {
self._local = ObservedObject(initialValue: Local(on))
print("test view5 init, glabel on = \(Global.shared.on), local on = \(self.local.on)")
}
您真的想在每次SwiftUI需要刷新其视图时使用不同的(独立的)模型吗?我不这么认为...
答案 1 :(得分:0)
Apple在iOS14中为此提供了一个新的解决方案:@StateObject,它与@State for Class一样,可安慰ObservableObject。
答案 2 :(得分:-1)
最后,我找到了原因。
@ObservedObject与@State不同。苹果在@State上做了一些特殊的工作。 @State将被保留在独立于视图的特殊空间中。
每次刷新UI时,都会初始化@ObservedObject。它无法恢复@State之类的值。
因此,使用@State而不是@ObservedObject。