I'm an iOS developer and I'm guilty of having Massive View Controllers in my projects so I've been searching for a better way to structure my projects and came across the MVVM (Model-View-ViewModel) architecture. I've been reading a lot of MVVM with iOS and I have a couple of questions. I'll explain my issues with an example.
I have a view controller called LoginViewController
.
LoginViewController.swift
import UIKit
class LoginViewController: UIViewController {
@IBOutlet private var usernameTextField: UITextField!
@IBOutlet private var passwordTextField: UITextField!
private let loginViewModel = LoginViewModel()
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func loginButtonPressed(sender: UIButton) {
loginViewModel.login()
}
}
It doesn't have a Model class. But I did create a view model called LoginViewModel
to put the validation logic and network calls.
LoginViewModel.swift
import Foundation
class LoginViewModel {
var username: String?
var password: String?
init(username: String? = nil, password: String? = nil) {
self.username = username
self.password = password
}
func validate() {
if username == nil || password == nil {
// Show the user an alert with the error
}
}
func login() {
// Call the login() method in ApiHandler
let api = ApiHandler()
api.login(username!, password: password!, success: { (data) -> Void in
// Go to the next view controller
}) { (error) -> Void in
// Show the user an alert with the error
}
}
}
My first question is simply is my MVVM implementation correct? I have this doubt because for example I put the login button's tap event (
loginButtonPressed
) in the controller. I didn't create a separate view for the login screen because it has only a couple of textfields and a button. Is it acceptable for the controller to have event methods tied to UI elements?My next question is also about the login button. When the user taps the button, the username and password values should gte passed into the LoginViewModel for validation and if successful, then to the API call. My question how to pass the values to the view model. Should I add two parameters to the
login()
method and pass them when I call it from the view controller? Or should I declare properties for them in the view model and set their values from the view controller? Which one is acceptable in MVVM?Take the
validate()
method in the view model. The user should be notified if either of them are empty. That means after the checking, the result should be returned to the view controller to take necessary actions (show an alert). Same thing with thelogin()
method. Alert the user if the request fails or go to the next view controller if it succeeds. How do I notify the controller of these events from the view model? Is it possible to use binding mechanisms like KVO in cases like this?What are the other binding mechanisms when using MVVM for iOS? KVO is one. But I read it's not quite suitable for larger projects because it require a lot of boilerplate code (registering/unregistering observers etc). What are other options? I know ReactiveCocoa is a framework used for this but I'm looking to see if there are any other native ones.
All the materials I came across on MVVM on the Internet provided little to no information on these parts I'm looking to clarify, so I'd really appreciate your responses.