swiftui - SwiftUI:@Environment 未在视图层次结构中接收提供的值
问题描述
我正在按照这个项目的示例创建我的 iOS 应用程序(感谢 Alexey!),但无法让 @Environment 变量接收正在向下传递 UI 层次结构的值。顶级视图接收正确的值,但下游视图接收该default
值。
编辑:绑定复制 Asperi 的代码后,我发现这种行为仅在通过NavigationLink
. 更新了以下代码:
EDIT2:问题environment
在于调用方法的位置。调用它NavigationView
而不是MainView
解决问题。代码更新如下:
自定义环境键 -DIContainer
struct DIContainer: EnvironmentKey {
let interactor: Interactor
init(interactor: Interactor) {
self.interactor = interactor
}
static var defaultValue: Self { Self.default }
private static let `default` = Self(interactor: .stub)
}
extension EnvironmentValues {
var injected: DIContainer {
get { self[DIContainer.self] }
set { self[DIContainer.self] = newValue }
}
}
App
结构
private let container: DIContainer
init() {
container = DIContainer(interactor: RealInteractor())
}
var body: some Scene {
WindowGroup {
NavigationView {
MainView()
}
.environment(\.injected, container)
}
主视图
struct MainView: View {
@Environment(\.injected) private var injected: DIContainer
// `injected` has the `RealInteractor`, as expected
var body: some View {
VStack {
Text("Main: \(injected.foo())") \\ << Prints REAL
NavigationLink(destination: SearchView()) {
Text("Search")
}
}
}
}
搜索视图
struct SearchView: View {
@Environment(\.injected) private var injected: DIContainer
// `injected` has the `StubInteractor`, why?
var body: some View {
Text("Search: \(injected.foo())")
}
}
我可以通过如下修改来解决这个问题MainView
:
var body: some View {
SearchView()
.environment(\.injected, container)
}
但是避免重复这样做的目的不是@Environment
吗?
任何指导/指针表示赞赏。
解决方案
我已经尝试复制所有部分并编译它们......结果就像预期的那样工作 - 环境在视图层次结构中向下传递,因此您可能会错过真实代码中的某些内容。
这是完整的模块,使用 Xcode 12.4 / iOS 14.4 测试
class Interactor { // << replicated !!
static let stub = Interactor()
func foo() -> String { "stub" }
}
class RealInteractor: Interactor { // << replicated !!
override func foo() -> String { "real" }
}
struct ContentView: View { // << replicated !!
private let container: DIContainer
init() {
container = DIContainer(interactor: RealInteractor())
}
var body: some View {
NavigationView {
MainView()
}
.environment(\.injected, container) // << to affect any links !!
}
}
// no changes in env parts
struct DIContainer: EnvironmentKey {
let interactor: Interactor
init(interactor: Interactor) {
self.interactor = interactor
}
static var defaultValue: Self { Self.default }
private static let `default` = Self(interactor: .stub)
}
extension EnvironmentValues {
var injected: DIContainer {
get { self[DIContainer.self] }
set { self[DIContainer.self] = newValue }
}
}
struct MainView: View {
@Environment(\.injected) private var injected: DIContainer
// `injected` has the `RealInteractor`, as expected
var body: some View {
SearchView()
}
}
// just tested here
struct SearchView: View {
@Environment(\.injected) private var injected: DIContainer
var body: some View {
Text("Result: \(injected.interactor.foo())") // << works fine !!
}
}
推荐阅读
- kubernetes - 使用完整的主机名进行 Apache Flink akka 监控
- string - 火花阵列
长度为 3 的数组 长度为一 - r - 基于列表元素循环函数
- sql-server - *为更多解释而编辑...*我需要 SQL 中一列的值,但这些值由有多少不同的值分隔
- scala - 如何在 Seq 中累积结果以供以后在 spark 中处理?
- javascript - Bootstrap轮播无法显示多个项目
- pyspark - 如何检查一个短语是否是英文的
- delphi - 子类化firemonkey表单后找不到资源
- python - 通过python在窗口服务中提示shell
- javascript - 使用 php 和 javascript 处理动态下拉框