符合ObservableObject的SwiftUI类应该是Singleton吗?

时间:2020-09-18 12:18:33

标签: swift swiftui singleton observableobject

我在SwiftUI中被视为newby,并且具有以下ViewModel。但我不确定MyViewModel是否应为单例。用法正确吗?符合ObservableObject的最佳实践/用法是什么?

class MyViewModel: ObservableObject {
    static let shared: MyViewModel = MyViewModel()
    
    @Published var result: String = ""
    
    private init() { }
    
    // some functions
}

struct ContentView: View {
    @ObservedObject private var vm = MyViewModel.shared
    
    var body: some View {
        Text(vm.result)
    }
}

2 个答案:

答案 0 :(得分:1)

为什么您认为viewmodel应该是单身人士?特别是,为什么ObservableObject一致性类需要一个单例实例?那是个坏主意。

这不仅绝对没有必要,这还意味着您无法在没有共享状态的情况下在屏幕上拥有同一视图的多个实例。如果要支持分屏并同时在屏幕上运行两个应用程序场景,则在iPad上尤其如此。

除非绝对必要,否则不要使任何事情变得单调。

@ObservedObject上存储View到SwiftUI @ObservedObject时要记住的唯一重要事项是,永远不要在视图内部对其进行初始化。当@Published发生更改(或其View属性之一更改)时,存储它的View将被重新加载。这意味着,如果您在struct ContentView: View { // Never do this @ObservedObject private var vm = MyViewModel() var body: some View { Text(vm.result) } } 内创建对象,则每当对象更新时,视图本身都会创建该对象的新实例。

所以这是个坏主意,将无法正常工作

View

相反,您需要将视图模型注入到ContentView中(无论从何处创建struct ParentView: View { @State private var childVM = MyViewModel() var body: some View { ContentView(vm: childVM) } } struct ContentView: View { @ObservedObject private var vm: MyViewModel // Proper way of injecting the view model init(vm: MyViewModel) { self.vm = vm } var body: some View { Text(vm.result) } } ,都可以在父视图或协调器中创建它)。

Point.java

答案 1 :(得分:0)

我以这种方式实现了我的方案。我们可以说这是正确的方法吗?谢谢...

struct RootTabView: View {
    @State var tabSelection = 0
    @State private var listVM = ListViewModel()
    
    var body: some View {
        TabView(selection: $tabSelection) {
            ListView(vm: listVM).tabItem({
                Text("Tab 1")
            }).tag(0)
            
            //Some other tabs
        }
    }
}

struct ListView: View {
    @ObservedObject var vm: ListViewModel
    
    var body: some View {
        NavigationView {
            List(vm.toDoList, id: \.self) { toDo in
                NavigationLink(destination: DetailView(vm: vm)) {
                    Text(toDo)
                }
            }
        }
        .onAppear {
            vm.getList()
        }
    }
}

struct DetailView: View {
    @ObservedObject var vm: ListViewModel
    
    var body: some View {
        Text(vm.toDoItem)
            .onAppear {
                vm.getDetail()
            }
    }
}

class ListViewModel: ObservableObject {
    @Published var toDoList: [String] = []
    @Published var toDoItem: String = ""
    
    func getList() {
        toDoList = ["a", "b", "c"]
    }
    
    func getDetail() {
        // do some stuffs
        toDoItem = "A"
    }
}