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

SwiftUI:为每个视图使用不同的环境对象,swiftui,swift5,Swiftui,Swift5,在SwiftUI中,我有两个不同的屏幕。对于每个屏幕,我都有一个ViewController、SwiftUI视图和一个组合环境对象。组合的EnvironmentObject有两个可观察的类,一个是ViewModel,另一个是Interactior 在不使用ViewController的情况下,如何为每个SwiftUI视图使用Interactior和ViewModel?每个视图都有不同的EnvironmentObject import SwiftUI import Combine class V

在SwiftUI中,我有两个不同的屏幕。对于每个屏幕,我都有一个ViewController、SwiftUI视图和一个组合环境对象。组合的EnvironmentObject有两个可观察的类,一个是ViewModel,另一个是Interactior

在不使用ViewController的情况下,如何为每个SwiftUI视图使用Interactior和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)
                })
            }
    }
}
导入快捷界面
进口联合收割机
类ViewModel1:ObservableObject{
//已发布数据以供查看
@已发布的变量文本:字符串
初始化(文本:字符串){
self.text=文本
}
}
类Interactor1:ObservableObject{
让vc:vc
是否让viewModel:ViewModel1?
init(vc:vc,viewModel:ViewModel1?){
self.vc=vc
self.viewModel=viewModel
}
func按钮单击(){
//使用vc显示第二个ViewController。显示。。。
}
}
类组合对象:ObserveObject{
@已发布的变量交互器:交互器1
@已发布的var viewModel:ViewModel1
var anycancelable:anycancelable?=nil
var ANYCANCELABLE2:ANYCANCELABLE?=nil
init(vc:vc,索引:Int){
viewModel=ViewModel1(文本:“text1”)
interactor=Interactor1(vc:vc,viewModel:nil)
interactor=Interactor1(vc:vc,viewModel:viewModel)
AnyCancelable=Interactior.objectWillChange.sink{(\u1)in
self.objectWillChange.send()
}
AnyCancelable2=viewModel.objectWillChange.sink{(\u1)in
self.objectWillChange.send()
}
}
}
类ViewController1:UIViewController{
重写func viewDidLoad(){
super.viewDidLoad()
让combinedObject=combinedObject(vc:self,索引:0)
让view1=view1().environmentObject(组合对象)
让hostingController=UIHostingController(rootView:view1)
self.addChild(主机控制器)
hostingController.view.translatesAutoresizingMaskIntoConstraints=false
self.view.addSubview(hostingController.view)
hostingController.didMove(toParent:self)
}
}
结构视图1:视图{
@环境对象变量combinedObject:combinedObject
var body:一些观点{
VStack(){
按钮(操作:{
self.combinedObject.interactior.buttonClicked()
},标签:{
文本(self.combinedObject.viewModel.Text)
})
}
}
}

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

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

    ...
顺序并不重要,因为是按类型注入的


使用Xcode 11.2/iOS 13.2进行测试,这意味着我将在显示根视图之前加载所有屏幕的数据。也许这是不可能做到我试图实现的,但这种方式至少不能真正很好地工作,因为它是昂贵的,没有必要加载很多甚至可能不需要的数据(对于不想访问所有视图的用户)。视图可能会在需要时调用某些方法来设置环境数据?无论如何,我只是对如何在不使用vc部件的情况下很好地设置体系结构有点困惑。@DevB2F,等等。。。在组合对象中你没有做同样的事情吗?我以为你只是想分开。。。而且,这只是一种设置环境的机制,您不必一次加载所有内容,有些内容可以是惰性的,有些内容可以是最近注入的,有些内容可以是可计算的,等等。这只是一种在层次结构中的任何地方都可以设置引用的可能性。其他一切都在你的控制之下。
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(...))