SwiftUI和MVVM设计模式

3

我正试图弄清楚如何使用MVVM设计模式和SwiftUI实现以下内容。

我想要只有一个网络操作队列的实例(使用OperationQueue),任何需要发送网络请求的视图模型都可以使用该队列。但我听说创建单例不是首选,而应该将网络队列对象传递到需要它的地方。

因此,如果我在Scene Delegate中创建网络操作队列的实例,并将其传递到ContentView的初始化程序中并将其存储在一个对象中以传递到所创建的视图中。

从我理解的角度来看,这似乎不是很好的MVVM设计实践,因为视图应仅拥有ViewModel?

那么最好的实现方式是什么呢?

编辑:我再考虑一下这个问题,我可以通过构造函数将它传递到视图中,然后在构造函数中创建视图模型并直接传递它,这样视图就不拥有任何东西。

但我仍然需要一个单例,那么我如何将单例作为依赖项注入而不是全局使用它呢?


我在我的应用程序中使用MVVM架构,整个应用程序都是开源的(正在进行中)。这是设置界面(SettingsView),其中我将ViewModel注入到View中,而ViewModel具有依赖项。Screen仅是View的类型别名。链接为:https://github.com/radixdlt/radixdlt-swift/blob/xcode11/ExampleWallet/Source/Code/Screens/Main/Settings/SettingsScreen.swift - Sajjon
1个回答

5
仅为了获得全局变量而创建单例是不合适的,但并不意味着我们永远不应该使用它们。在您的情况下,如果我理解正确,您基本上正在创建一个可被整个应用程序使用的服务。您可以选择 A) 创建一个具有所需网络功能的可重用类(并在需要实例化它的任何地方)或 B) 创建一个包含单例实例的类,在任何地方都可以轻松访问。 如果你需要维护所有调用者共同状态或等待队列,单例将是更好的选择。

选项A

class NetworkService {

    init() {
        // init
    }

    // Your properties and methods
    func someFunction() {}
}

在ViewModel中的使用:

let networkService = NetworkService()
networkService.someFunction()
选项 B
class NetworkService {
    static let shared = NetworkService()
    private let queue : Any?

    // Your properties and methods
    func someFunction() {}
}

使用方法:

NetworkService.shared.someFunction()

无论哪种方式,这仍然是MVVM。数据与任何特定视图或特定模型无关;它只是一个服务,在需要时在任何ViewModel中调用。

谢谢,这证实了我的想法 - 选择第二个选项! - Michael
在视图模型中使用 NetworkService.shared.someFunction() 会使你的视图模型难以测试。不要使用单例。 - Darko
嗨@Darko,感谢您的意见。您能详细解释一下为什么它是不可测试的吗?我很想了解原因。谢谢! - rfarias
4
因为视图模型将尝试在单元测试中调用单例。这意味着需要进行真正的网络调用。您需要将网络服务作为协议注入。因此,为网络服务创建一个协议,并将网络服务实例注入到视图模型init中。在单元测试中,您可以创建一个MockNetworkService,该服务遵循相同的协议并进行注入。您的模拟当然不会进行真正的网络调用。这是松耦合和依赖项注入的基本原则。 - Darko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接