Currently I'm developing an iOS application by using MVVMC architecture. I was getting some idea about MVVMC by reading this article . As a typical MVVM model we know all the major app controllers like web service calls should call in the ViewModel class. But in the MVVMC architecture we can user either Coordinator or ViewModel to call web services. I couldn't figure out what's the best place for this.
I'm currently trying to implement user list page of the application using UITableViewController. Following are the some parts of my UserCoordinator and UserViewModel classes.
UserCoordinator
class UsersCoordinator: Coordinator {
var window: UIWindow
weak var delegate: UsersCoordinatorDelegate?
var selectedCity: City?
init(window: UIWindow) {
self.window = window
}
func start() {
let storyboard = UIStoryboard(name: "Users", bundle: nil)
if let vc = storyboard.instantiateViewController(withIdentifier: "list") as? UsersListController {
var viewModel = UsersListViewModel()
viewModel.delegate = self as UsersListViewModelDelegate
viewModel.veiwController = vc
vc.viewModel = viewModel
vc.coordinationDelegate = self as CoordinationDelegate
let nav = UINavigationController.init(rootViewController: vc)
window.rootViewController = nav
}
}
UserViewModel
protocol UsersListViewModelDelegate: class {
func selectUser(viewController: UIViewController, city: City)
}
struct UsersListViewModel {
var delegate: UsersListViewModelDelegate?
weak var veiwController: UsersListController!
var source = [String]()
init() {
for user in users {
source.append(user.name)
}
}
func selectRow(row: NSInteger) {
delegate?.selectUser(viewController: veiwController, user: users[row])
}
fileprivate var users: [User] {
get {
//web service call??
}
Where should I call the web service here? As I have read theoretically Coordinator is the dedicated place for application routing. So according to that it's better to call web services in ViewModel. But I feel it's better to call web services in the Coordinator because it'll load data very quickly and populate the viewModel. What should I do?
You need to understand the purpose of ViewModel and Co-ordinator to know what should contains what. The responsibility of a ViewModel is to prepare data for the View and handles the business logic for preparing that data. It binds data to UI elements and changes UI as soon as data changes. So ViewModel should be the one which should contains the service and all calls should be made from it.
The responsibility of co-ordinator is to handles the navigation of application by showing the appropriate ViewController with all it's dependencies which includes the ViewModel. So it also prepares the ViewModel and injects the service in it not use that service to manipulate data.
So if I summarise, Co-ordinator should be the one who prepares a ViewModel with it's dependencies which includes the injecting webservice in it and ViewModel should be the one who use that service and makes all the call for getting data from the persistence .
For more clear idea you can check my sample application on MVVM-C at my Github
As I researched through the internet there is no convention where to invoke your web services. It's totally depend on your project implementation. Either you can invoke them on your Coordinator or ViewModel class. Since we are using Coordinator to initialize
Inside the Coordinator class as I have posted above. We can use same start() function to invoke the web services as following.
func start() {
let storyboard = UIStoryboard(name: "Users", bundle: nil)
if let vc = storyboard.instantiateViewController(withIdentifier: "list") as? UsersListController {
let uDs = UserDataService(pClient:APIClient())
uDs.getUserDetails { (response, status) in
if (status == APIClient.APIResponseStatus.Success) {
if let resArrray = response as? [User] {
var viewModel = UsersListViewModel.init(userList: resArrray)
viewModel.delegate = self as UsersListViewModelDelegate
viewModel.veiwController = vc
vc.viewModel = viewModel
vc.coordinationDelegate = self as CoordinationDelegate
let nav = UINavigationController.init(rootViewController: vc)
self.window.rootViewController = nav
}
} else {
//error alert
}
}
}
}
It's better to invoke web service calls inside the Coordinator class. Because after invokes the web service according to the response we can controll the view navigation. Such like if response get success we could create a ViewController class and load it. Otherwise we could load an error popup. Meantime we could take enough time to the web service call and populate those data to the viewModel.
Based on what I have found through the internet , I have implemented a sample project using MVVM-C architecture. I have hosted it in GitHub. You can find it in here.
By refering this poroject you can have a clear idea about to how to implement view navigations using MVVM-C pattern, How to invoke web services, How to populate viewModels from data etc.
When it comes to architecture, there's no silver bullet. Keeping that in mind MVVM-C is one of the most clean, easily testable and modular pattern, so it's great that you are going ahead with it.
You are free to customize the architecture to suit your requirements. Having said that, considering your current design I think it would be best to create a Service class, call it WebService. This class will perform networking operations under the supervision of the Coordinator. The Coordinator will
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With