[在SwiftUI中更新父视图时如何避免在工作表中调用init()

问题描述 投票:0回答:1

TestView3可以显示2张纸:TestView4和TestView5。 TestView4具有@State值,该值从TestView3初始化。 TestView5也具有@ObservedObject值,该值也从TestView3初始化。

当我切换全局值(global.on)时,它将更新TestView3,然后导致TestView4或TestView5 init()。

Q1。 TestView3更新时,如何避免在TestView4或TestView5中调用init()?如何完全隔离带有视图的工作表与视图?否则视图中的任何更新都会影响工作表,这很糟糕。

Q2。 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()
        }
    }
}
swiftui
1个回答
0
投票

Q1:您无法避免。为什么?每次包装在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需要刷新其视图时使用不同的(独立的)模型?我不这么认为...

© www.soinside.com 2019 - 2024. All rights reserved.