3

I am trying to get my head round how i can achive the following using the MVVM design pattern with SwiftUI.

I want to have only 1 instance of a networking operation queue (using OperationQueue) where any view model that needs to send any networking requests but i have heard that creating a Singleton is not preferred and i should be passing the networking queue object around where it is needed.

So if i create the instance of the network operation queue in the Scene Delegate and pass them into the ContentView initialiser and store it in an object there to then pass into the views then created.

This doesnt seem like good MVVM design practice as from what i understand the View should Own the ViewModel only?

What is the best way of achieving this?

Edit: thought a bit more about this and I can pass it into the view via its constructor and then within the constructor I can create the view model and pass it straight through so the view doesn’t own anything.

But I still will require a singleton so how can I pass the singleton as a dependency injection rather than using it globally?

1
  • I use MVVM in my app, the whole all is open source (work in progress), this is the SettingsView (SettingsScreen, Screen is just a Type alias for View right now), where I inject the ViewModel into the View, and the ViewModel has dependencies: github.com/radixdlt/radixdlt-swift/blob/xcode11/ExampleWallet/… Commented Aug 29, 2019 at 21:39

1 Answer 1

5

We shouldn’t create singletons for the single reason of being an easy way to get global variables, but it doesn’t mean we should never use them.

In your case, if I understood correctly, you are basically creating a service that can be used by the entire application. You could either A) create a reusable class with the networking functions you need (and instantiate anywhere you need it) or B) create a class with a singleton instance in it, that can be easily accessed anywhere.

A singleton would be a better choice if you need to keep some state common to all callers, or if you need to maintain a waiting queue, for example.

Option A

class NetworkService {

    init() {
        // init
    }

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

Usage in a ViewModel:

let networkService = NetworkService()
networkService.someFunction()

Option B

class NetworkService {
    static let shared = NetworkService()
    private let queue : Any?

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

Usage:

NetworkService.shared.someFunction()

Either way, this is still MVVM. The data is not related to any specific view, nor to a specific model; it's simply a service you would call in any ViewModel that needs it.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for this, this confirms my thoughts - option 2 it is!
Using NetworkService.shared.someFunction() in the view model makes your view model untestable. Don't use singletons.
Hi @Darko, thanks for the input. Could you elaborate a little more on why it would be untestable? Would love to understand the reason. Thanks!
Because the view model would try to call the singleton in the unit test. Which means doing a real network call. What you want is injecting the network service as a protocol. So create a protocol for the network service and inject an instance of the network service into the view model init. In unit tests you create a MockNetworkService which adheres to the same protocol and inject that one. Your Mock of course does not do a real network call. This are the basic principles of loose coupling and dependency injection.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.