简体   繁体   English

在 SwiftUI 组件之间共享 ViewModel

[英]Sharing ViewModel between SwiftUI components

I'd like to implement a navigator/router for an architecture implemented with SwiftUI and Combine.我想为使用 SwiftUI 和 Combine 实现的架构实现导航器/路由器。 In a few words the View will share viewModel with Router .简而言之, View将与Router共享viewModel When the View triggers a change on the viewModel the Router should navigate to a new sheet.View触发的改变viewModelRouter应该导航到新的工作表。

This is a version of my code where I'm directly passing the viewModel from View to Router .这是我的代码的一个版本,我直接将viewModelView传递到Router Is there anything wrong?有什么不对的吗? My biggest doubt is that since I'm using @ObservedObject on both the Router and the View , two different instances of the viewModel are created.我最大的疑问是,由于我在RouterView上都使用了@ObservedObject ,因此创建了两个不同的viewModel实例。

VIEW MODEL查看模型

class BootViewModel:ObservableObject{
    @Published var presentSignIn = false
}

VIEW看法

struct BootView: View {

    @ObservedObject var viewModel:BootViewModel
    var navigator:BootNavigator<BootView>? = nil

    init(viewModel:BootViewModel) {
        self.viewModel = viewModel
        self.navigator = BootNavigator(view: self, viewModel: viewModel)
        self.navigator.setSubscriptions()
    }

    var body: some View {
        VStack{
            Text("Hello")
            Button("Button"){
                self.viewModel.presentSignIn.toggle()
            }
        }
    }
}

NAVIGATOR航海家

class BootNavigator<T:View>{
    var view:T? = nil
    @ObservedObject var viewModel:BootViewModel

    init(view:T, viewModel:BootViewModel) {
        self.view = view
        self.viewModel = viewModel
    }

    func setSubscriptions(){
        subscribe(onSigninPressed: $viewModel.presentSignIn)
    }


    func subscribe(onSigninPressed : Binding<Bool>){
        _ = view.sheet(isPresented: $viewModel.presentSignIn){
            SignInView()
        }
    }
}
  • Why the SignInView is never presented?为什么SignInView永远不会出现?
  • Without taking into account the fact that using a router with swiftUI is not needed in general(I'm mostly doing an exercise)... is there anything wrong with this implementation?没有考虑到一般不需要使用带有 swiftUI 的路由器这一事实(我主要是在做练习)……这个实现有什么问题吗?

This这个

view.sheet(isPresented: $viewModel.presentSignIn){
    SignInView()

MUST be somewhere in body (directly or via computed property or func) but inside body's ViewBuilder必须body某个地方(直接或通过计算属性或 func)但在 body 的 ViewBuilder 内

Some notes I have to point out here:我必须在这里指出的一些注意事项:

ValueType值类型

There is a difference between an UIView and a SwiftUI View . UIView和 SwiftUI View之间存在差异。 All SwiftUI View s are value type!所有 SwiftUI View都是值类型! So they get copied when you pass them around.因此,当您传递它们时,它们会被复制。 Be aware of that.请注意这一点。

Single instance单实例

If you want a single instance like a regular navigator for your entire app, you can use singleton pattern.如果你想要一个单一的实例,比如整个应用程序的常规导航器,你可以使用单例模式。 But there is a better approach in SwiftUI universe called @Environment objects.但是 SwiftUI 宇宙中有一种更好的方法,称为@Environment对象。 You can take advantage of that.你可以利用这一点。

Trigger a view refresh触发视图刷新

To refresh the view (including presenting something), you must code inside the var body .要刷新视图(包括呈现某些内容),您必须var body编码。 But it can be directly written on indirectly through a function or etc.但它可以通过函数等间接写入。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM