MVVM — iOS

BN
iOS World
Published in
4 min readJan 24, 2023
Photo by AltumCode on Unsplash

Model-View-ViewModel (MVVM) is a design pattern that is similar to Model-View-Controller (MVC) but with an additional component called the ViewModel.

  • Model: The Model represents the data and the business logic of the application, similar to MVC. It is responsible for storing and manipulating the data, and it is typically implemented using classes or structs.
  • View: The View is responsible for displaying the data to the user and handling user input. It is usually implemented using classes such as UIView or UIViewController in iOS.
  • ViewModel: The ViewModel acts as an intermediary between the Model and the View. It is responsible for handling the data transformations, handling the presentation logic and providing a simplified version of the data to the View. It also receives user interactions from the View and updates the Model accordingly.
  • Controller : In MVVM, controller is not mandatory and the ViewModel takes the role of the controller.

The main advantage of MVVM is that it allows for better separation of concerns and makes it easier to test the code. Also, it helps to keep the View simple and easy to understand, as it does not contain any complex business logic.

MVVM pattern is widely used in iOS development for building scalable and maintainable apps.

Example of an iOS application using the Model-View-ViewModel (MVVM) pattern:

class Model {
var data: [String] = []
func addData(newData: String) {
data.append(newData)
}
}

class ViewModel {
var model: Model
var data: [String] {
return model.data
}
init(model: Model) {
self.model = model
}

func addData(newData: String) {
model.addData(newData: newData)
}
}

class ViewController: UIViewController {
var viewModel: ViewModel!
@IBOutlet weak var tableView: UITableView!

override func viewDidLoad() {
super.viewDidLoad()
let model = Model()
viewModel = ViewModel(model: model)
}

@IBAction func addDataButtonTapped(_ sender: UIButton) {
let alert = UIAlertController(title: "Add Data", message: nil, preferredStyle: .alert)
alert.addTextField { (textField) in
textField.placeholder = "Enter new data"
}
let addAction = UIAlertAction(title: "Add", style: .default) { _ in
if let data = alert.textFields?.first?.text {
self.viewModel.addData(newData: data)
self.tableView.reloadData()
}
}
alert.addAction(addAction)
present(alert, animated: true, completion: nil)
}
}

extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewModel.data.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = viewModel.data[indexPath.row]
return cell
}
}

Here is a simple example of an iOS application using the Model-View-ViewModel (MVVM) pattern:

Copy code
class Model {
var data: [String] = []
func addData(newData: String) {
data.append(newData)
}
}

class ViewModel {
var model: Model
var data: [String] {
return model.data
}
init(model: Model) {
self.model = model
}

func addData(newData: String) {
model.addData(newData: newData)
}
}

class ViewController: UIViewController {
var viewModel: ViewModel!
@IBOutlet weak var tableView: UITableView!

override func viewDidLoad() {
super.viewDidLoad()
let model = Model()
viewModel = ViewModel(model: model)
}

@IBAction func addDataButtonTapped(_ sender: UIButton) {
let alert = UIAlertController(title: "Add Data", message: nil, preferredStyle: .alert)
alert.addTextField { (textField) in
textField.placeholder = "Enter new data"
}
let addAction = UIAlertAction(title: "Add", style: .default) { _ in
if let data = alert.textFields?.first?.text {
self.viewModel.addData(newData: data)
self.tableView.reloadData()
}
}
alert.addAction(addAction)
present(alert, animated: true, completion: nil)
}
}

extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewModel.data.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = viewModel.data[indexPath.row]
return cell
}
}

In this example, the Model class represents the data and business logic of the application, the ViewModel class represents the intermediary between the Model and the View, and the tableView represents the View. The ViewController class uses the ViewModel class to add new data, and updates the tableView to display the data to the user. The ViewModel class also handles the data transformation if needed.

Pros and Cons

Pros:

  • Better separation of concerns: MVVM separates the presentation logic from the business logic, making the code more organized and easier to maintain.
  • Improved testability: Because the ViewModel is responsible for handling the presentation logic, it can be easily tested without the need for a user interface.
  • Simplified views: The View does not contain any complex business logic, making it easier to understand and modify.
  • Reusability: The ViewModel can be reused across multiple views, making it easier to manage common functionality.

Cons:

  • Increased complexity: Because MVVM introduces an additional component (the ViewModel), the overall architecture of the application becomes more complex.
  • Increased boilerplate code: MVVM requires more code than MVC, which can make the development process more time-consuming.
  • Learning curve: Developers need to learn and understand the MVVM pattern before they can effectively use it.

It’s important to note that the choice of architecture pattern should be based on the specific requirements and constraints of the project. The MVVM pattern may not be suitable for small or simple applications.

--

--