在SwiftUI组件之间共享ViewModel

时间:2019-12-20 11:13:43

标签: swift swiftui combine

我想为使用SwiftUI和Combine实现的架构实现导航器/路由器。简而言之,View将与viewModel共享Router。当View触发viewModel上的更改时,Router应该导航到新工作表。

这是我的代码的一个版本,我在其中直接将viewModelView传递到Router。有什么问题吗?我最大的疑问是,由于我在@ObservedObjectRouter上都使用View,因此创建了viewModel的两个不同实例。

查看模型

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

查看

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()
            }
        }
    }
}

导航器

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()
        }
    }
}
  • 为什么从未显示SignInView
  • 没有考虑到通常不需要在swiftUI上使用路由器的事实(我主要是在做练习)...此实现有什么问题吗?

2 个答案:

答案 0 :(得分:2)

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

必须(直接或通过计算属性或函数)位于body中的某个位置,但位于主体的ViewBuilder中

答案 1 :(得分:2)

一些注意事项,我必须在这里指出:

ValueType

set /p choice=和SwiftUI UIView之间是有区别的。所有SwiftUI View都是值类型!因此,当您传递它们时,它们将被复制。注意这一点。

单个实例

如果您想要整个应用程序使用一个像常规 navigator 这样的实例,则可以使用单例模式。但是SwiftUI Universe中有一种更好的方法称为View对象。您可以利用它。

触发视图刷新

要刷新视图(包括显示内容),必须在@Environment内部中进行编码。但是它可以直接通过函数等间接编写。