使用NavigationLink更新EnvironmentObject刷新/移交问题

时间:2020-07-01 18:20:57

标签: xcode data-binding swiftui watchos swiftui-navigationlink

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

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

完成配置过程后,用户应单击按钮以返回“主”应用程序(主视图)。为了控制相同层次结构上的视图,我的计划是将EnvironmentObject(据我所知,一旦注入,将EnvironmentObject移交给子视图,并且子视图可以使用EnvironmentObject)与“控制视图”结合使用它控制视图的显示。因此,我遵循了该教程:https://blckbirds.com/post/how-to-navigate-between-views-in-swiftui-by-using-an-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()
            }
        }
    }
}

AppStateControl.swift

class AppStateControl: ObservableObject {
    @Published var callView: String = "AppConfig"
}

AppConfig.swift

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")
            }
        }
    }
}

AppMain.swift

struct AppMain: View {
    var body: some View {
        Text("Main App")
    }
}

在我的代码的先前版本中(没有一直移交EnvironmentObject),我遇到了运行时错误(“线程1:致命错误:未找到AppStateControl类型的ObservableObject。View.environmentObject( AppStateControl的_ :)作为此视图的祖先可能会丢失。“ )由AppConfig.swift中的第41行引起。在互联网上,我读到这可能是NavigationLink的错误(请参阅:https://www.hackingwithswift.com/forums/swiftui/environment-object-not-being-inherited-by-child-sometimes-and-app-crashes/269https://twitter.com/twostraws/status/1146315336578469888)。因此,建议将环境对象显式传递给NavigationLink的目的地(在实现上)。不幸的是,这也不起作用,而是单击“ DetailView2” 中的“转到主应用”按钮会导致视图“ DetailView1” 而不是 “ AppMain”

任何想法如何解决这个问题?在我看来,通过导航链接调用的视图中的EnvironmentObject的更改似乎无法(正确)刷新视图。

谢谢。

1 个答案:

答案 0 :(得分:0)

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

this.state.selectValue.map((item) => {
  return(
    <div className="row m-3">
      <label className="col-md-4">{item}</label>
      <div className="col-md-7">
        <input type="text" name={item} className="form-control"  />
      </div>
    </div>
   )                                                    
})


 <Select
    isMulti
    options={this.state.options}
    onChange = {(e) => this.onChange(e)}
    classNamePrefix="select"
 /> 

然后,您可以使用此变量通过设置class AppStateControl: ObservableObject { ... @Published var isDetailActive = false // <- add this } 参数来控制第一个NavigationLink。另外,您需要向所有后续链接中添加isActive

堆栈中的第一个链接:

.isDetailLink(false)

所有其他链接:

NavigationLink(destination: DetailView1().environmentObject(appStateControl), isActive: self.$appStateControl.isDetailActive) {
    Text("Show Detail View 1")
}
.isDetailLink(false)

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

false