DEV Community

Tauan Camargo
Tauan Camargo

Posted on

Building Robust iOS User Interfaces with MVVM: A Guide for SwiftUI and UIKit Developers

Model-View-ViewModel (MVVM) is a popular design pattern for developing user interfaces in iOS applications. MVVM separates the user interface logic from the business logic, which makes the code more modular and easier to maintain. In this article, we'll explore how to implement MVVM in iOS development using both SwiftUI and UIKit.

What is MVVM?

MVVM is a design pattern that separates the user interface (View) from the business logic (Model) by introducing a new layer, the ViewModel. The ViewModel acts as a mediator between the View and the Model, providing data and business logic to the View and updating the Model based on user input from the View.

The key benefits of using MVVM in iOS development are:

Improved modularity: The code is more modular and easier to maintain, as the business logic is separated from the user interface.
Better testability: The ViewModel can be easily unit tested, as it is a separate layer with a clear responsibility.
More flexible user interface: The ViewModel provides the data and business logic to the View, allowing for more flexibility in how the user interface is designed and presented.
Implementing MVVM in SwiftUI
To implement MVVM in SwiftUI, we can follow these steps:

Define the Model: The Model represents the data and business logic of the application. We can define it as a simple struct or class that conforms to the Codable protocol.

Define the ViewModel: The ViewModel acts as a mediator between the View and the Model. It provides the data and business logic to the View, and updates the Model based on user input from the View. We can define it as an ObservableObject class that contains the data and methods required by the View.

Define the View: The View is responsible for presenting the user interface to the user. We can define it as a SwiftUI View that observes the data provided by the ViewModel and updates its own state based on changes in the ViewModel.

Here's an example of how to implement MVVM in SwiftUI:

// Define the Model
struct User: Codable {
    var name: String
    var age: Int
}

// Define the ViewModel
class UserViewModel: ObservableObject {
    @Published var user: User

    init(user: User) {
        self.user = user
    }

    func updateName(_ name: String) {
        user.name = name
    }

    func updateAge(_ age: Int) {
        user.age = age
    }
}

// Define the View
struct UserView: View {
    @ObservedObject var viewModel: UserViewModel

    var body: some View {
        VStack {
            TextField("Name", text: $viewModel.user.name)
            TextField("Age", value: $viewModel.user.age, formatter: NumberFormatter())
        }
    }
}

// Usage
let user = User(name: "John", age: 30)
let viewModel = UserViewModel(user: user)
UserView(viewModel: viewModel)
Enter fullscreen mode Exit fullscreen mode

In this example, we define the User Model as a simple struct with two properties: name and age. We then define the UserViewModel as an ObservableObject class that contains the User Model and two methods for updating its properties. Finally, we define the UserView as a SwiftUI View that observes the UserViewModel and updates its own state based on changes in the ViewModel.

Implementing MVVM in UIKit

To implement MVVM in UIKit, we can follow a similar approach:

Define the Model: The Model represents the data and business logic of the application. We can define it as a simple struct or class that conforms to the Codable protocol.

Define the ViewModel: The ViewModel acts as a mediator between the View and the Model. It provides the data and business logic to the View, and updates the Model based on user input from the View. We can define it as a class that contains the data and methods required by the View.

Define the View: The View is responsible for presenting the user interface to the user. We can define it as a UIViewController or a UIView that observes the data provided by the ViewModel and updates its own state based on changes in the ViewModel.

Here's an example of how to implement MVVM in UIKit:

// Define the Model
struct User: Codable {
    var name: String
    var age: Int
}

// Define the ViewModel
class UserViewModel {
    var user: User

    init(user: User) {
        self.user = user
    }

    func updateName(_ name: String) {
        user.name = name
    }

    func updateAge(_ age: Int) {
        user.age = age
    }
}

// Define the View
class UserViewController: UIViewController {
    var viewModel: UserViewModel!

    @IBOutlet weak var nameTextField: UITextField!
    @IBOutlet weak var ageTextField: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()
        bindViewModel()
    }

    private func bindViewModel() {
        nameTextField.text = viewModel.user.name
        ageTextField.text = String(viewModel.user.age)

        nameTextField.addTarget(self, action: #selector(nameTextFieldDidChange(_:)), for: .editingChanged)
        ageTextField.addTarget(self, action: #selector(ageTextFieldDidChange(_:)), for: .editingChanged)
    }

    @objc private func nameTextFieldDidChange(_ textField: UITextField) {
        viewModel.updateName(textField.text ?? "")
    }

    @objc private func ageTextFieldDidChange(_ textField: UITextField) {
        if let age = Int(textField.text ?? "") {
            viewModel.updateAge(age)
        }
    }
}

// Usage
let user = User(name: "John", age: 30)
let viewModel = UserViewModel(user: user)
let viewController = UserViewController()
viewController.viewModel = viewModel
Enter fullscreen mode Exit fullscreen mode

In this example, we define the User Model as a simple struct with two properties: name and age. We then define the UserViewModel as a class that contains the User Model and two methods for updating its properties. Finally, we define the UserViewController as a UIViewController that observes the UserViewModel and updates its own state based on changes in the ViewModel.

Conclusion

In this article, we've explored how to implement MVVM in iOS development using both SwiftUI and UIKit. By separating the user interface logic from the business logic, MVVM makes the code more modular, easier to maintain, and better testable. Whether you're using SwiftUI or UIKit, MVVM is a powerful design pattern that can help you create robust and flexible user interfaces in your iOS applications.

Top comments (2)

Collapse
 
stoiandan profile image
Stoian Dan • Edited

This is nice! However, it starts to show, I think, that MVVM is a Microsoft construct for XAML.
In your example, the updateAge and updateName functions of the VM, aren't really used, since the TextField view takes a binding to the fields.
Thus really only a model should have sufficed.
However, sometimes, things do begin to be more complicated and messy.
I really think Apple should step-in and provide a name and model for us all.

Collapse
 
tauantcamargo profile image
Tauan Camargo

for sure