Friday, 6 October 2023

MVC, MVVM, and MVP design patterns in Swift

 Hello everyone! I’m excited to share my knowledge about architecture design patterns which are (MVC, MVVM, and MVP) and how it works in Swift. 

# MVC stands for Model-View-Controller

The MVC architecture is straightforward to understand and quite easy to implement in UIKit. All architectures are created to make it easy, effective, flexible, and fast to develop our app and prevent many mistakes that developers can make without architecture.

Let’s dive into the MVC architecture and gain a deeper understanding of how it works šŸ”„

# M — Model
The “Model” is responsible for business logic, network calls, parse data, and so on. The “Model” does not need to know about the UI if you in the “Model” use UI attributes it means your architecture goes wrong.

# V — View
The ‘View’ is responsible for representing UI elements such as UILabel, UIView, UITextView, and so on. It should not have knowledge of the ‘Model.’ Including business logic and network calls within the ‘View’ indicates a problem in your architecture.

# C — Controller
The “Controller” acts as an intermediary between the “Model” and the “View”. It handles user input, communicates with the “Model” to fetch or update data, and updates the “View” accordingly. You can see the above image 🤷‍♂️

# The real example of MVC architecture in UIKit 🄶

You can check out my GitHub repository at the following link: šŸ‘‰ TodoListApp. The ‘TodoListApp’ is built using the MVC architecture.

For the “Model” check out this page.
For the “View” check out this page.
For the “Controller” check out this page.

# MVVM stands for Model-View-ViewModel

The MVVM architecture is quite similar to the MVC design pattern. While it shares many similarities with MVC, MVVM is widely used in SwiftUI, and it’s especially beneficial when working with the Combine framework.

# M — Model
The “Model” in MVVM is similar to the “Model” in MVC. It represents the data and business logic of the application. It defines how data is structured and manipulated. In Swift, the “Model” can be implemented using classes, structs, or enums.

# V — View
The “View” in MVVM is also similar to the “View” in MVC. It represents the only UI elements and the “View” should only display data, and handle user interactions, without containing application logic(business logic).

# VM — View-Model
The “ViewModel” acts as a mediator between the “Model” and the “View”. The “ViewModel” is responsible for preparing and formatting data from the “Model” for presentation in the “View”. “ViewModels” also handles user input and interactions. They contain the business logic needed for specific views.

# The real example of MVVM architecture in UIKit 🄶

# Model

struct Task {
var title: String
var completed: Bool
}

# ViewModel

class TaskListViewModel {
private var tasks: [Task] = [
Task(title: "Buy groceries", completed: false),
Task(title: "Read a book", completed: true),
Task(title: "Exercise", completed: false)
]

var taskCount: Int {
return tasks.count
}

func task(at index: Int) -> Task {
return tasks[index]
}

func addTask(title: String) {
let newTask = Task(title: title, completed: false)
tasks.append(newTask)
}

func toggleTask(at index: Int) {
tasks[index].completed.toggle()
}
}

# View

import UIKit

class TaskListViewController: UIViewController {
@IBOutlet private var tableView: UITableView!
@IBOutlet private var taskTextField: UITextField!

private var viewModel = TaskListViewModel()

override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
}

@IBAction private func addButtonTapped() {
guard let taskTitle = taskTextField.text, !taskTitle.isEmpty else { return }
viewModel.addTask(title: taskTitle)
taskTextField.text = ""
tableView.reloadData()
}
}

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

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TaskCell", for: indexPath)
let task = viewModel.task(at: indexPath.row)
cell.textLabel?.text = task.title
cell.accessoryType = task.completed ? .checkmark : .none
return cell
}
}
  1. Task represents the “Model”, which defines the structure of a task.
  2. TaskListViewModel is the “ViewModel”, responsible for managing tasks, adding tasks, and updating their completion status.
  3. TaskListViewController is the “View”, which displays the list of tasks in a table view and allows the user to add new tasks. It communicates with the ViewModel to perform these tasks.

# MVP stands for Model-View-Presenter

The MVP architecture is also similar to MVC architecture the same “Model” layer, “View” layer, and additional “Presenter”. However, the MVP design pattern has one difference from the MVC design pattern. Now the ViewController(Controller layer) is considered as a view. which means it will include only the view-related code, nothing more and all logic will be implemented in the presenter.

  • View: The “View” includes both view and view controllers, taking care of setting up the user interface and handling user interactions and all events.
  • Presenter: The “Presenter” handles all the logic, such as responding to user actions and updating the UI through the Protocols and Delegates. An important aspect is that our presenter is UIKit-independent, making it well-isolated and easily testable.
  • Model: The “Model” role will be exactly the same in MVC architecture.

# The real example of MVP architecture in UIKit 🄶

# Model

// Model: Represents a task
struct Task {
var title: String
var description: String
}

# View

// View: Displays task information
class TaskViewController: UIViewController {
@IBOutlet private var titleLabel: UILabel!
@IBOutlet private var descriptionLabel: UILabel!

private var presenter: TaskPresenterProtocol!

convenience init(presenter: TaskPresenterProtocol) {
self.init()
self.presenter = presenter
}

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

private func configureView() {
let task = presenter.fetchTask()
titleLabel.text = task.title
descriptionLabel.text = task.description
}

@IBAction private func completeButtonTapped() {
presenter.taskCompleted()
}
}

# Presenter

// Presenter: Manages the interaction between Model and View
protocol TaskPresenterProtocol {
func fetchTask() -> Task
func taskCompleted()
}

class TaskPresenter: TaskPresenterProtocol {
private var task: Task

init(task: Task) {
self.task = task
}

func fetchTask() -> Task {
return task
}

func taskCompleted() {
// Perform logic to mark the task as completed
}
}
  • Task: The task represents the “Model”, which defines the structure of a task.
  • TaskPresenter: The TaskPresenter is the “Presenter”, which manages the interaction between the “Model” and the “View”. It provides methods to fetch task data and mark tasks as completed.
  • TaskViewController: The TaskViewController is the “View”, which displays the task information and handles user interactions. It receives a TaskPresenterProtocol instance and uses it to fetch and update task data.

No comments:

Post a Comment