符合ObservableObject的SwiftUI类应该是Singleton?

gmxoilav  于 2023-04-28  发布在  Swift
关注(0)|答案(2)|浏览(147)

我在SwiftUI中被认为是纽比,我有下面的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)
    }
}
lymnna71

lymnna711#

为什么你认为视图模型应该是单例的?特别是,为什么一个符合ObservableObject的类需要一个单例示例?这是个坏主意
这不仅是绝对不必要的,而且还意味着您不能在屏幕上拥有同一视图的多个示例,而它们没有共享状态。这在iPad上尤其糟糕,如果你想支持分屏,并在屏幕上同时运行你的应用程序的2个场景。
不要让任何东西都成为单例,除非你绝对不得已。
在SwiftUI View s上存储@ObservedObject s时,唯一需要记住的重要事情是,它们永远不应该在视图中初始化。当@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)
    }
}
yfjy0ee7

yfjy0ee72#

我就是用这种方式实现我的场景的。我们能说这是正确的方式吗?

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"
    }
}

相关问题