Xcode 环境使用NavigationLink时对象刷新/移交问题

Xcode 环境使用NavigationLink时对象刷新/移交问题,xcode,data-binding,swiftui,watchos,swiftui-navigationlink,Xcode,Data Binding,Swiftui,Watchos,Swiftui Navigationlink,我目前正在macOS Catalina上使用XCode 11.5中的Swift/SwiftUI为watchOS 6(独立应用程序)开发一个应用程序 在用户可以使用我的应用程序之前,需要进行配置过程。由于配置过程由几个不同的视图组成,这些视图一个接一个地显示,因此我使用导航链接实现了这一点 配置过程完成后,用户应单击按钮返回“主”应用程序(主视图)。对于控制处于同一层次级别的视图,我的计划是使用EnvironmentObject(据我所知,一个EnvironmentObject一旦被注入,就会被交

我目前正在macOS Catalina上使用XCode 11.5中的Swift/SwiftUI为watchOS 6(独立应用程序)开发一个应用程序

在用户可以使用我的应用程序之前,需要进行配置过程。由于配置过程由几个不同的视图组成,这些视图一个接一个地显示,因此我使用导航链接实现了这一点

配置过程完成后,用户应单击按钮返回“主”应用程序(主视图)。对于控制处于同一层次级别的视图,我的计划是使用EnvironmentObject(据我所知,一个EnvironmentObject一旦被注入,就会被交给子视图,子视图可以使用EnvironmentObject)与控制视图显示的“控制视图”相结合。因此,我遵循了教程:

这是我的代码:

ContentView.swift

struct ContentView: View {
    var body: some View {
        ContentViewManager().environmentObject(AppStateControl())        
    }
}

struct ContentViewManager: View {
    @EnvironmentObject var appStateControl: AppStateControl
    
    var body: some View {
        VStack {
            if(appStateControl.callView == "AppConfig") {
                AppConfig()
            }
            if(appStateControl.callView == "AppMain") {
                AppMain()
            }
        }
    }
}
class AppStateControl: ObservableObject {
    @Published var callView: String = "AppConfig"
}
struct AppConfig: View {
    @EnvironmentObject var appStateControl: AppStateControl
    var body: some View {
        VStack {
            Text("App Config Main")
            NavigationLink(destination: DetailView1().environmentObject(appStateControl)) {
                Text("Show Detail View 1")
            }
        }
    }
}

struct DetailView1: View {
    @EnvironmentObject var appStateControl: AppStateControl
    var body: some View {
        VStack {
            Text("App Config Detail View 1")
            NavigationLink(destination: DetailView2().environmentObject(appStateControl)) {
                Text("Show Detail View 2")
            }
        }
    }
}

struct DetailView2: View {
    @EnvironmentObject var appStateControl: AppStateControl
    var body: some View {
        VStack {
            Text("App Config Detail View 2")
            Button(action: {
                self.appStateControl.callView = "AppMain"
            }) {
             Text("Go to main App")
            }
        }
    }
}
struct AppMain: View {
    var body: some View {
        Text("Main App")
    }
}
AppStateControl.swift

struct ContentView: View {
    var body: some View {
        ContentViewManager().environmentObject(AppStateControl())        
    }
}

struct ContentViewManager: View {
    @EnvironmentObject var appStateControl: AppStateControl
    
    var body: some View {
        VStack {
            if(appStateControl.callView == "AppConfig") {
                AppConfig()
            }
            if(appStateControl.callView == "AppMain") {
                AppMain()
            }
        }
    }
}
class AppStateControl: ObservableObject {
    @Published var callView: String = "AppConfig"
}
struct AppConfig: View {
    @EnvironmentObject var appStateControl: AppStateControl
    var body: some View {
        VStack {
            Text("App Config Main")
            NavigationLink(destination: DetailView1().environmentObject(appStateControl)) {
                Text("Show Detail View 1")
            }
        }
    }
}

struct DetailView1: View {
    @EnvironmentObject var appStateControl: AppStateControl
    var body: some View {
        VStack {
            Text("App Config Detail View 1")
            NavigationLink(destination: DetailView2().environmentObject(appStateControl)) {
                Text("Show Detail View 2")
            }
        }
    }
}

struct DetailView2: View {
    @EnvironmentObject var appStateControl: AppStateControl
    var body: some View {
        VStack {
            Text("App Config Detail View 2")
            Button(action: {
                self.appStateControl.callView = "AppMain"
            }) {
             Text("Go to main App")
            }
        }
    }
}
struct AppMain: View {
    var body: some View {
        Text("Main App")
    }
}
AppConfig.swift

struct ContentView: View {
    var body: some View {
        ContentViewManager().environmentObject(AppStateControl())        
    }
}

struct ContentViewManager: View {
    @EnvironmentObject var appStateControl: AppStateControl
    
    var body: some View {
        VStack {
            if(appStateControl.callView == "AppConfig") {
                AppConfig()
            }
            if(appStateControl.callView == "AppMain") {
                AppMain()
            }
        }
    }
}
class AppStateControl: ObservableObject {
    @Published var callView: String = "AppConfig"
}
struct AppConfig: View {
    @EnvironmentObject var appStateControl: AppStateControl
    var body: some View {
        VStack {
            Text("App Config Main")
            NavigationLink(destination: DetailView1().environmentObject(appStateControl)) {
                Text("Show Detail View 1")
            }
        }
    }
}

struct DetailView1: View {
    @EnvironmentObject var appStateControl: AppStateControl
    var body: some View {
        VStack {
            Text("App Config Detail View 1")
            NavigationLink(destination: DetailView2().environmentObject(appStateControl)) {
                Text("Show Detail View 2")
            }
        }
    }
}

struct DetailView2: View {
    @EnvironmentObject var appStateControl: AppStateControl
    var body: some View {
        VStack {
            Text("App Config Detail View 2")
            Button(action: {
                self.appStateControl.callView = "AppMain"
            }) {
             Text("Go to main App")
            }
        }
    }
}
struct AppMain: View {
    var body: some View {
        Text("Main App")
    }
}
AppMain.swift

struct ContentView: View {
    var body: some View {
        ContentViewManager().environmentObject(AppStateControl())        
    }
}

struct ContentViewManager: View {
    @EnvironmentObject var appStateControl: AppStateControl
    
    var body: some View {
        VStack {
            if(appStateControl.callView == "AppConfig") {
                AppConfig()
            }
            if(appStateControl.callView == "AppMain") {
                AppMain()
            }
        }
    }
}
class AppStateControl: ObservableObject {
    @Published var callView: String = "AppConfig"
}
struct AppConfig: View {
    @EnvironmentObject var appStateControl: AppStateControl
    var body: some View {
        VStack {
            Text("App Config Main")
            NavigationLink(destination: DetailView1().environmentObject(appStateControl)) {
                Text("Show Detail View 1")
            }
        }
    }
}

struct DetailView1: View {
    @EnvironmentObject var appStateControl: AppStateControl
    var body: some View {
        VStack {
            Text("App Config Detail View 1")
            NavigationLink(destination: DetailView2().environmentObject(appStateControl)) {
                Text("Show Detail View 2")
            }
        }
    }
}

struct DetailView2: View {
    @EnvironmentObject var appStateControl: AppStateControl
    var body: some View {
        VStack {
            Text("App Config Detail View 2")
            Button(action: {
                self.appStateControl.callView = "AppMain"
            }) {
             Text("Go to main App")
            }
        }
    }
}
struct AppMain: View {
    var body: some View {
        Text("Main App")
    }
}
在以前版本的代码中(没有始终移交EnvironmentObject),我遇到了一个运行时错误(“线程1:致命错误:未找到AppStateControl类型的ObservableObject。AppStateControl的View.EnvironmentObject(:)可能作为此视图的祖先丢失。”),这是由AppConfig.swift中的第41行引起的。在互联网上,我读到这可能是NavigationLink的一个bug(请参阅:,)。因此,建议显式地将EnvironmentObject传递到NavigationLink的目标(上面的实现)。不幸的是,这也不起作用,而是点击“DetailView2”中的“Go to main App”(转到主应用程序)按钮将导致视图“DetailView1”而不是“AppMain”

有没有办法解决这个问题?在我看来,在通过导航链接调用的视图中更改EnvironmentObject似乎不会刷新视图(正确)


提前感谢。

解决方案之一是创建一个变量,控制是否显示导航堆栈

class AppStateControl: ObservableObject {
    ...
    @Published var isDetailActive = false // <- add this
}
所有其他链接:

NavigationLink(destination: DetailView2().environmentObject(appStateControl)) {
    Text("Show Detail View 2")
}
.isDetailLink(false)
然后只需将
isDetailActive
设置为
false
即可弹出所有导航链接并返回主视图:

Button(action: {
    self.appStateControl.callView = "AppMain"
    self.appStateControl.isDetailActive = false // <- add this
}) {
    Text("Go to main App")
}
按钮(操作:{
self.appStateControl.callView=“AppMain”

self.appStateControl.isDetailActive=false/解决方案之一是创建一个变量来控制是否显示导航堆栈

class AppStateControl: ObservableObject {
    ...
    @Published var isDetailActive = false // <- add this
}
所有其他链接:

NavigationLink(destination: DetailView2().environmentObject(appStateControl)) {
    Text("Show Detail View 2")
}
.isDetailLink(false)
然后只需将
isDetailActive
设置为
false
即可弹出所有导航链接并返回主视图:

Button(action: {
    self.appStateControl.callView = "AppMain"
    self.appStateControl.isDetailActive = false // <- add this
}) {
    Text("Go to main App")
}
按钮(操作:{
self.appStateControl.callView=“AppMain”

self.appStateControl.isDetailActive=false//感谢您的快速回复!我刚刚实现了解决方案,但是,应用程序的行为与以前相同。不幸的是,.isdetailink(false)在watchOS中不可用。关于如何解决此问题或为什么我的应用程序会这样做,还有其他想法吗?@JPF哦,我明白了,我的错。你可以看到这个问题,我认为这也解释了如何在watchOS上工作。想法是一样的-你需要回到导航堆栈的根目录,以显示
AppMain
,而不是
>AppConfig
。感谢您的快速回复!我刚刚实现了解决方案,但是,应用程序的行为与以前相同。不幸的是,.isDetailLink(false)在watchOS中不可用。关于如何解决此问题或为什么我的应用程序会这样做,还有其他想法吗?@JPF哦,我明白了,我的错。你可以看到这个问题,我认为这也解释了如何在watchOS上工作。想法是一样的-你需要回到导航堆栈的根目录,以显示
AppMain
,而不是
>AppConfig