'Can I use MVVM without data binding?
I am trying to use MVVM. Upon reading some blogs on MVVM, I found them using data binding techniques like Rx, KVO, Boxing etc. Following are my classes for validating user using MVVM. I have not put any code for data binding. What I do is simply pass the username and password from viewcontroller to my view model class upon the submit button click. The view model consists all the logic for validation. And at the end, it returns the status to the viewcontroller, depending on which the view controller shows some message. I am wandering is this the way to go or should some data binding be used?
SignUpViewController.swift
import UIKit
class SignUpViewController: UIViewController {
let signupviewmodel = SignUpViewModel()
@IBOutlet weak var textFieldUsername: UITextField!
@IBOutlet weak var textFieldPassword: UITextField!
@IBOutlet weak var textFieldPasswordConfirm: UITextField!
@IBAction func initialSignUp(_ sender: Any) {
signupviewmodel.updateUsername(username: textFieldUsername.text!)
signupviewmodel.updatePassword(password: textFieldPassword.text!)
signupviewmodel.updateConfirmPassword(confirmpassword: textFieldPasswordConfirm.text!)
switch signupviewmodel.validateUser() {
case .Valid:
showAlert(title: "Valid", message: "success")
case .InValid(let error):
showAlert(title: "Error Validation", message: error)
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func showAlert(title: String, message: String) -> Void {
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
SignUpViewModel.swift
import Foundation
enum UserValidationState {
case Valid
case InValid(String)
}
class SignUpViewModel {
private let minPasswordLength: Int = 6
private var user = User()
var username: String {
return user.username!
}
var password: String {
return user.password!
}
var confirmpassword: String {
return user.confirmpassword!
}
}
extension SignUpViewModel {
func updateUsername(username: String) {
user.username = username
}
func updatePassword(password: String) {
user.password = password
}
func updateConfirmPassword(confirmpassword: String) {
user.confirmpassword = confirmpassword
}
func validateUser() -> UserValidationState {
if (username.isBlank || password.isBlank || confirmpassword.isBlank) {
return .InValid("Please fill all the fields")
} else {
if isNumber(username: username) {
if isValidPhone(phone: username) {
if isValidPasswordLength(password: password) {
if passwordsMatch(password: password, confirmpassword: confirmpassword) {
return .Valid
}
return .InValid("Passwords do not match")
}
return .InValid("Password length doesn't meet criteria")
}
return .InValid("InValid Phone")
} else {
if isValidEmail(email: username) {
if isValidPasswordLength(password: password) {
if passwordsMatch(password: password, confirmpassword: confirmpassword) {
return .Valid
}
return .InValid("Passwords do not match")
}
return .InValid("Password length doesn't meet criteria")
}
return .InValid("InValid Email")
}
}
}
func isValidEmail(email:String) -> Bool {
let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,6}"
return NSPredicate(format:"SELF MATCHES %@", emailRegEx).evaluate(with: email)
}
func isValidPhone(phone: String) -> Bool {
return true
}
func isBlank(text: String) -> Bool {
return text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
}
func isValidPasswordLength(password: String) -> Bool {
guard password.count < minPasswordLength else {
return true
}
return false
}
func passwordsMatch(password: String, confirmpassword: String) -> Bool {
guard password == confirmpassword else {
return false
}
return true
}
func isNumber(username: String) -> Bool {
guard let _ = Int(username) else {
return false
}
return true
}
}
User.swift
import Foundation
struct User {
var username: String?
var password: String?
var confirmpassword: String?
}
Solution 1:[1]
Data binding is the foundation of MVVM. So data binding helps you to keep all the business logic out of Views and work asynchronously with sending and receiving data. It would seem ok that you're passing values to viewModel, but there are cases when you will need to pass values from ViewModels to ViewControllers. For example, you have asynchronous API request which responds some data. In MVVM you would store that data in your ViewModel, but your ViewController needs to be notified that some data was received. Data binding helps to solve those cases with less amount of code. Yes, you can work without data binding just by using callbacks, but that would mean that you have to write a lot of boilerplate code.
I understand that KVO, Rx and Reactive seem to be difficult. So, you can start with simple libraries which offer only binding functionality, without getting deep into complex stuff. Check out these libraries:
https://github.com/ReactiveKit/Bond
https://github.com/blendle/Hanson
And just for note, the way you coded is more like MVP(Model View Presenter). You can check that design architecture if you don't like reactive programming.
Solution 2:[2]
Can I use MVVM without data binding?
Short Answer:
Yes.
Explain:
The main idea of using MVVM is to not have a reference to the view so that you can reuse this VM in several places easily but you can reference the view as a state change only and have an access to the VM properties if needed to use it when VM notifies the view about the state change.
Example:
https://www.codementor.io/@nishadhshrestha/mvvm-in-swift-4-using-delegates-ikdflt1cb
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Utemissov |
Solution 2 | Essam Fahmi |