SwiftUI NavigationView 在更新 observableObject 时弹回

SwiftUI NavigationView pops back when updating observableObject

背景: 几天来我一直被这个烦人的问题困扰,尝试不同的解决方案并在 Whosebug 等中搜索答案;有些人遇到过类似的问题,但没有建议的解决方案达到预期的效果。

问题是,在导航层次结构视图堆栈中向下更新 observableObject 或 environmentObject 时,视图会弹出回根目录。从 observableObject 查看数据可以,但不能编辑。

场景是:

  1. 我导航到:root -> view1 -> view2。
  2. 我在 View2 中更新了 environmentObject 但随后我被推回到:root -> view1

我简化了我的应用程序以使其更易于理解。见下文:

ObservableObject:

class DataStore: ObservableObject {
    static let shared = dataStore() 
    @Published var name   : String = ""
}

根视图:

struct ContentView: View {
   @StateObject var dataStore = DataStore.shared
   @State private var isShowingView1 = false
    var body: some View {
        NavigationView{
            VStack{
                Text(dataStore.name)
                NavigationLink(destination: View1(), isActive: $isShowingView1) { }
                Button(action: {
                    isShowingView1 = true
                })
            }
        }
    }
}

视图 1:

struct View1: View {
    @EnvironmentObject var dataStore: dataStore
    @State private var isShowingView2 = false
    var body: some View {
        ScrollView{
            VStack(alignment: .center) {
                Text(dataStore.name)
                NavigationLink(destination: View2(), isActive: $isShowingView2) { }
                Button(action: {
                    isShowingView2 = true
                }){
                    Text("Go to View2")
                }
            }
        }
    }
}

视图 2:

struct View2: View {
    @EnvironmentObject var dataStore: dataStore
    var body: some View {
        ScrollView{
            VStack(alignment: .center) {
                Text(dataStore.name)
                Button(action: {
                    dataStore.name = "updated value"
                }){
                    Text("Update data")
                }
                // When updating this environmentObject the viewstack will be pushed back to View1. If view2 had been navigated to view3 and the view3 had been updating the environmentObject, then it would also be pushed back to View1.
            }
        }
    }
}

解法: 我花了很多时间寻找解决方案并尝试不同的方法,但我尝试过的都没有奏效。似乎还有其他一些人遇到了与我遇到的问题相同的问题,但建议的解决方案并没有解决问题。 但是后来我在尝试实现另一个功能时偶然发现了这个问题的解决方案。所以坦率地说,我现在写在这里,不是向这个伟大的社区寻求帮助,而是通过向可能需要看到这个的其他人提供这个解决方案来回馈社区。

该解决方案实现起来非常简单,但并不容易实现。如果您遇到与我类似的问题,那么您只需要相应地更新您的 rootView:

根视图已更新:

struct ContentView: View {
   @StateObject var dataStore = DataStore.shared
   @State private var isShowingView1 = false
    var body: some View {
        NavigationView{
            VStack{
                Text(dataStore.name)
                NavigationLink(destination: View1(), isActive: $isShowingView1) { }
                Button(action: {
                    isShowingView1 = true
                })
            }
        }
        .navigationViewStyle(.stack)
        //ADD THIS LINE ABOVE
    }
}

这一行 .navigationViewStyle(.stack) 为我解决了弹出视图堆栈的问题。不幸的是,我无法为您提供此行为的逻辑解释,但它有效并且我对此感到满意。也许你也是,或者也许你已经了解为什么这个解决方案实际上达到了允许视图在层次结构中更新 observableObjects 而不被弹出的预期效果。

该解决方案实现起来非常简单,但并不容易实现。如果您遇到与我类似的问题,那么您只需要相应地更新您的 rootView:

根视图已更新:

struct ContentView: View {
   @StateObject var dataStore = DataStore.shared
   @State private var isShowingView1 = false
    var body: some View {
        NavigationView{
            VStack{
                Text(dataStore.name)
                NavigationLink(destination: View1(), isActive: $isShowingView1) { }
                Button(action: {
                    isShowingView1 = true
                })
            }
        }
        .navigationViewStyle(.stack)
        //ADD THIS LINE ABOVE
    }
}

这一行 .navigationViewStyle(.stack) 为我解决了弹出视图堆栈的问题。不幸的是,我无法为您提供此行为的逻辑解释,但它有效并且我对此感到满意。