符合 ObservableObject 的 SwiftUI 类应该是 Singleton?

Ken*_*Nur 7 singleton swift swiftui observableobject

我被认为是 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)
    }
}
Run Code Online (Sandbox Code Playgroud)

Dáv*_*tor 5

为什么你认为视图模型应该是单例的?特别是,为什么ObservableObject一致性类需要单例实例?这是个坏主意。

这不仅是绝对没有必要的,而且还意味着如果没有共享状态,您就不能在屏幕上拥有同一视图的多个实例。如果您想支持分屏并同时在屏幕上运行应用程序的 2 个场景,这在 iPad 上尤其糟糕。

除非绝对必要,否则不要将任何东西设置为单例。

@ObservedObject在 SwiftUI 上存储时要记住的唯一重要的事情View是它们永远不应该在视图内初始化。当某个@ObservedObject更改(或其属性之一@Published更改)时,View它将重新加载存储。这意味着,如果您在 内部创建对象View,则每当对象更新时,视图本身都会创建该对象的新实例。

所以这是一个坏主意并且行不通:

struct ContentView: View {
    // Never do this
    @ObservedObject private var vm = MyViewModel()
    
    var body: some View {
        Text(vm.result)
    }
}
Run Code Online (Sandbox Code Playgroud)

相反,您需要将视图模型注入到您的视图中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)
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 只是指出,在 iOS 14 中,如果您希望视图模型不被父级注入,您现在可以使用“@StateObject”。 (5认同)