无法在视图之间共享环境

时间:2019-07-27 22:49:10

标签: swiftui combine

环境:Xcode版本11.0 beta 4(11M374r)

我无法与第二个观点分享“环境”。

我已在SceneDelegate中实例化了环境BindableObject:

SceneDelegate.swift: enter image description here

我在基础(ContentView)和详细视图中都使用@EnvironmentObject。

该环境已经在SceneDelegate中设置,因此它应可用于所有视图。

ContentView确实看到了环境。
但是DetailView爆炸了: enter image description here

这是完整的代码:

import Combine
import SwiftUI

struct UserInfo {
    var name: String
    var message: String
    init(name: String, msg: String) {
        self.name = name; self.message = msg
    }
}

// A BindableObject is always a class; NOT a struct.
class UserSettings: BindableObject {
    let willChange = PassthroughSubject<Void, Never>()
    var userInfo = UserInfo(name: "Ric", msg: "Mother had a feeling, I might be too appealing.") {
        didSet {
            willChange.send()
        }
    }
}

// =====================================================================================================

struct DetailView: View {
    @Binding var dismissFlag: Bool
    @EnvironmentObject var settings: UserSettings  // ...<error source>

    var body: some View {
        VStack {
            Spacer()
            Button(action: dismiss) {
                Text("Dismiss")
                    .foregroundColor(.white)
            }
            .padding()
            .background(Color.green)
            .cornerRadius(10)
            .shadow(radius: 10)

            Text("Hello")
            Spacer()
        }
    }

    private func dismiss() {
        settings.userInfo.message = "Rubber baby buggy bumpers."
        dismissFlag = false
    }
}

// ---------------------------------------------------------------------------
// Base View:

struct ContentView: View {
    @State var shown = false
    @EnvironmentObject var settings: UserSettings

    var body: some View {
        VStack {
            Spacer()
            Button(action: {
                self.settings.userInfo.name = "Troglodyte"
                self.settings.userInfo.message = "Top Secret"
                self.shown.toggle()
            }) {
                Text("Present")
                    .foregroundColor(.white)
            }.sheet(isPresented: $shown) { DetailView(dismissFlag: self.$shown) }
                .padding()
                .background(Color.red)
                .cornerRadius(10)
                .shadow(radius: 10)
            Text(self.settings.userInfo.message)
            Spacer()
        }
    }
}

// =====================================================================================================

#if DEBUG
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
#endif

我想念什么?
我在做什么错了?


每个建议的修订:

import SwiftUI
import UIKit

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    var window: UIWindow?
    var userSettings = UserSettings()

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {

        // Use a UIHostingController as window root view controller
        if let windowScene = scene as? UIWindowScene {
            let window = UIWindow(windowScene: windowScene)
            window.rootViewController = UIHostingController(rootView: ContentView().environmentObject(userSettings))
            self.window = window
            window.makeKeyAndVisible()
        }
    }
}

修改SceneDelegate后出现运行时错误消息:

enter image description here


这是一个线索: enter image description here

1 个答案:

答案 0 :(得分:1)

SceneDelegate中,您需要声明变量的实例:

var userSettings = UserSettings()  // <<--- ADD THIS


func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    if let windowScene = scene as? UIWindowScene {
        let window = UIWindow(windowScene: windowScene)
        window.rootViewController = UIHostingController(rootView: ContentView()
            .environmentObject(userSettings)  <<-- CHANGE THIS
        )
        self.window = window
        window.makeKeyAndVisible()
    }
}

这将创建{/ {1}}的全局/环境实例。

编辑:

发生第二个错误,与将userSettings暴露给预览有关。对于this answer by @MScottWaller,您需要在@EnvironmentObject SceneDelegate中创建一个单独的实例。

PreviewProvider