带有 ObservableObject 属性 的 ObservableObject 未触发 SwiftUI 更新
ObservableObject with ObservableObject property is not triggering SwiftUI Update
// NavigationState.swift
class NavigationState: ObservableObject {
@Published var contentViewNavigation = ContentViewNavigationState()
//@Published var selectedTab = 0
}
// App.swift
@main
struct SwiftUIDeepLinkApp: App {
@StateObject private var navigationAppState = NavigationState()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(navigationAppState)
.onAppear(perform: {
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
print("Dispatch called")
navigationAppState.contentViewNavigation.selectedTab = 1
//navigationAppState.selectedTab = 1
}
})
}
}
}
// ContentView.swift
class ContentViewNavigationState: ObservableObject {
@Published var selectedTab = 0
}
struct ContentView: View {
@EnvironmentObject var navigationState: NavigationState
var body: some View {
TabView(selection: $navigationState.contentViewNavigation.selectedTab) {
HomeContainerFlow1()
.tabItem { Text("Flow 1") }
.tag(0)
HomeContainerFlow2()
.embededInNavigation()
.tabItem { Text("Flow 2") }
.tag(1)
}.onReceive(navigationState.contentViewNavigation.$selectedTab, perform: { output in
print("Value changed: \(output)")
})
}
}
如您所见,我定义了一个全局状态(“NavigationState”)来处理应用程序的导航(即选项卡选择)。因此,我有一个 ObservableObject (NavigationState),它将具有每个屏幕导航状态的属性(即 ContentViewNavigationState - 另一个 ObservableObject)。
实际行为
在这个例子中,我在 DispatchQueue.asyncAfter 中修改 App.swift 文件中的状态,状态正在改变(因为 ContentView 的 onReceive 修饰符正在显示更新值)但没有触发任何在 ContentView 中更新。
预期行为
所选选项卡应根据状态更改。
- 有趣的是,如果我还修改另一个 属性(即评论的
selectedTab
),在这种情况下会触发更新,但不会在仅更新 contentViewNavigation 的 属性.
如果对象已更改,如果想要更新,视图必须显式观察 ObservableObject。
在你的例子中,你观察到 observable 的 parent 而不是 inner observable。你场景中的 contentViewNavigation
本身并没有改变,因为它只是对内部对象的引用。
所以解决方案可能如下面的演示所示
struct ContentView: View {
@EnvironmentObject var navigationState: NavigationState
var body: some View {
// separate view which observe inner ObservableObject
MainView(contentNavigation: navigationState.contentViewNavigation)
}
}
struct MainView: View {
@ObservedObject var contentNavigation: ContentViewNavigationState
var body: some View {
TabView(selection: $contentNavigation.selectedTab) {
HomeContainerFlow1()
.tabItem { Text("Flow 1") }
.tag(0)
HomeContainerFlow2()
.embededInNavigation()
.tabItem { Text("Flow 2") }
.tag(1)
}
}
}
// NavigationState.swift
class NavigationState: ObservableObject {
@Published var contentViewNavigation = ContentViewNavigationState()
//@Published var selectedTab = 0
}
// App.swift
@main
struct SwiftUIDeepLinkApp: App {
@StateObject private var navigationAppState = NavigationState()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(navigationAppState)
.onAppear(perform: {
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
print("Dispatch called")
navigationAppState.contentViewNavigation.selectedTab = 1
//navigationAppState.selectedTab = 1
}
})
}
}
}
// ContentView.swift
class ContentViewNavigationState: ObservableObject {
@Published var selectedTab = 0
}
struct ContentView: View {
@EnvironmentObject var navigationState: NavigationState
var body: some View {
TabView(selection: $navigationState.contentViewNavigation.selectedTab) {
HomeContainerFlow1()
.tabItem { Text("Flow 1") }
.tag(0)
HomeContainerFlow2()
.embededInNavigation()
.tabItem { Text("Flow 2") }
.tag(1)
}.onReceive(navigationState.contentViewNavigation.$selectedTab, perform: { output in
print("Value changed: \(output)")
})
}
}
如您所见,我定义了一个全局状态(“NavigationState”)来处理应用程序的导航(即选项卡选择)。因此,我有一个 ObservableObject (NavigationState),它将具有每个屏幕导航状态的属性(即 ContentViewNavigationState - 另一个 ObservableObject)。
实际行为
在这个例子中,我在 DispatchQueue.asyncAfter 中修改 App.swift 文件中的状态,状态正在改变(因为 ContentView 的 onReceive 修饰符正在显示更新值)但没有触发任何在 ContentView 中更新。
预期行为
所选选项卡应根据状态更改。
- 有趣的是,如果我还修改另一个 属性(即评论的
selectedTab
),在这种情况下会触发更新,但不会在仅更新 contentViewNavigation 的 属性.
如果对象已更改,如果想要更新,视图必须显式观察 ObservableObject。
在你的例子中,你观察到 observable 的 parent 而不是 inner observable。你场景中的 contentViewNavigation
本身并没有改变,因为它只是对内部对象的引用。
所以解决方案可能如下面的演示所示
struct ContentView: View {
@EnvironmentObject var navigationState: NavigationState
var body: some View {
// separate view which observe inner ObservableObject
MainView(contentNavigation: navigationState.contentViewNavigation)
}
}
struct MainView: View {
@ObservedObject var contentNavigation: ContentViewNavigationState
var body: some View {
TabView(selection: $contentNavigation.selectedTab) {
HomeContainerFlow1()
.tabItem { Text("Flow 1") }
.tag(0)
HomeContainerFlow2()
.embededInNavigation()
.tabItem { Text("Flow 2") }
.tag(1)
}
}
}