在视图中重新实例化@EnvironmentObject

时间:2020-05-15 19:42:07

标签: swift swiftui combine

在我的应用程序中,我需要在轻按按钮时重新实例化@EnvironmentObject。正确的位置在哪里?

这是我的视图的屏幕截图-在“存档的对象”列表中,我想拥有不可变的对象。因此,当我点击Archive Object时,我想将当前对象添加到数组中并创建一个新的当前对象。

enter image description here

该应用程序的简化版本如下所示。

我在SceneDelegate中实例化该对象:

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?

    var myObject = MyObject()
    let myObjects = MyObjects()

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

        let contentView = ContentView()
            .environmentObject(myObject)
            .environmentObject(myObjects)

        if let windowScene = scene as? UIWindowScene {
            let window = UIWindow(windowScene: windowScene)
            window.rootViewController = UIHostingController(rootView: contentView)
            self.window = window
            window.makeKeyAndVisible()
        }
    }

    //.....
}

这是我的模特:

class MyObject: ObservableObject, Identifiable {
    @Published var id = UUID()
}

class MyObjects: ObservableObject {
    @Published var values: [MyObject] = [
        MyObject(),
        MyObject()
    ]
}

在我看来,我需要将当前对象放入一个(归档)数组,然后创建一个新的当前对象来使用。这是我正在尝试的:

struct ContentView: View {

    @EnvironmentObject var currentObject: MyObject
    @EnvironmentObject var objects: MyObjects

    var sceneDelegate: UISceneDelegate {
        guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
            let sd = windowScene.delegate as? SceneDelegate else { fatalError() }
        return sd
    }

    var body: some View {
        VStack {
            Form {
                Section(header: Text("Current Object")) {
                    Text(currentObject.id.uuidString)
                }
                Section(header: Text("Archived Objects")) {
                    List(objects.values, id: \.id) { object in
                        Text(object.id.uuidString)

                    }
                    Button(action: {
                        self.objects.values.append(self.currentObject)

// as the environment object is get only, I cannot reinstantiate it here...
//                        self.currentObject = MyObject()
                    }) {
                        Text("Archive Object")
                    }
                }
            }

            Spacer()
        }
    }
}

1 个答案:

答案 0 :(得分:0)

这是一个解决方案。查看内嵌评论。

通过Xcode 11.4 / iOS 13.4测试

demo

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {

        // Usage
        ContentView(current: MyObject())
            .environmentObject(MyObjects())
    }
}


struct ContentView: View {
    @EnvironmentObject var objects: MyObjects
    @State private var current: MyObject        // tracks current

    init(current: MyObject) {
        _current = State(initialValue: current)
    }

    var body: some View {
        // rebuilt on *current* changed
        ContentInnerView(current: $current)
            .environmentObject(current)
    }

    struct ContentInnerView: View {
        @Binding var current: MyObject   // change current

        @EnvironmentObject var objects: MyObjects
        @EnvironmentObject var currentObject: MyObject

        init(current: Binding<MyObject>) {
            _current = current
        }

        var sceneDelegate: UISceneDelegate {
            guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
                let sd = windowScene.delegate as? SceneDelegate else { fatalError() }
            return sd
        }

        var body: some View {
            VStack {
                Form {
                    Section(header: Text("Current Object")) {
                        Text(currentObject.id.uuidString)
                    }
                    Section(header: Text("Archived Objects")) {
                        List(objects.values, id: \.id) { object in
                            Text(object.id.uuidString)

                        }
                        Button(action: {
                            self.objects.values.append(self.currentObject)
                            self.current = MyObject() // << works !!
                        }) {
                            Text("Archive Object")
                        }
                    }
                }

                Spacer()
            }
        }
    }
}