SwiftUI:为每个视图使用不同的环境对象

时间:2020-02-28 11:07:44

标签: swiftui swift5

在SwiftUI中,我有几个不同的屏幕。对于每个屏幕,我都有一个ViewController,SwiftUI View和一个组合的EnvironmentObject。组合的EnvironmentObject具有两个可观察的类,一个是ViewModel,另一个是Interactor。

我如何在不使用ViewController的情况下为每个SwiftUI视图使用Interactor和ViewModel?每个视图都有一个不同的EnvironmentObject。

import SwiftUI
import Combine

class ViewModel1: ObservableObject {
    //Published data for view
    @Published var text: String

    init(text: String) {
        self.text = text
    }
}


class Interactor1<VC: UIViewController>: ObservableObject {

    let vc: VC
    let viewModel: ViewModel1?

    init(vc: VC, viewModel: ViewModel1?) {
        self.vc = vc
        self.viewModel = viewModel
    }

    func buttonClicked() {
        //present second ViewController by using vc.present...
    }
}


class CombinedObject<VC: UIViewController>: ObservableObject {
    @Published var interactor: Interactor1<VC>
    @Published var viewModel: ViewModel1

    var anyCancellable: AnyCancellable? = nil
    var anyCancellable2: AnyCancellable? = nil

    init(vc: VC, index: Int) {
        viewModel = ViewModel1(text: "text1")

        interactor = Interactor1(vc: vc, viewModel: nil)
        interactor = Interactor1(vc: vc, viewModel: viewModel)

        anyCancellable = interactor.objectWillChange.sink { (_) in
            self.objectWillChange.send()
        }

        anyCancellable2 = viewModel.objectWillChange.sink { (_) in
            self.objectWillChange.send()
        }
    }
}


class ViewController1: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let combinedObject = CombinedObject(vc: self, index: 0)
        let view1 = View1<ViewController1>().environmentObject(combinedObject)
        let hostingController = UIHostingController(rootView: view1)

        self.addChild(hostingController)
        hostingController.view.translatesAutoresizingMaskIntoConstraints = false
        self.view.addSubview(hostingController.view)
        hostingController.didMove(toParent: self)
    }
}


struct View1<VC1: UIViewController>: View {
    @EnvironmentObject var combinedObject: CombinedObject<VC1>

    var body: some View {
        VStack() {
            Button(action: {
                self.combinedObject.interactor.buttonClicked()
            }, label: {
                Text(self.combinedObject.viewModel.text)
                })
            }
    }
}

1 个答案:

答案 0 :(得分:0)

环境对象是按类型注入的,因此您可以分别注入视图模型和插入器,如下所示

struct View1<VC1: UIViewController>: View {
    @EnvironmentObject var viewModel: ViewModel1
    @EnvironmentObject var iterator: Interactor1<VC1>

    ...

,例如,所有子视图都可以使用它们(基于声明,两个子视图都可以独立使用)

struct SubView1<VC1: UIViewController>: View { // only with view model
    @EnvironmentObject var viewModel: ViewModel1

struct SubView2<VC1: UIViewController>: View { // only with iterator
    @EnvironmentObject var iterator: Interactor1<VC1>

最后,也是必需的,对于根视图,两个都必须注入到构造中,例如(抓痒的)

View1(...)
   .environmentObject(ViewModel1(...))
   .environmentObject(Interactor1(...))

顺序无关紧要,按类型插入。

通过Xcode 11.2 / iOS 13.2测试