How to Use Model-View-ViewModel (MVVM) in iOS | Architecture pattern in iOS | iOS design patterns Coding with Swift.




In this article, I would like to share a way to implement an MVVM design pattern. In the MVVM design pattern, the Model is that the same as in the MVC pattern. It represents simple data.

MVVM stands for "Model View ViewModel". MVVM isn't a design pattern. It’s a software architecture often used by Apple developers to exchange MVC.


Lets talk about the Differences between Architecture and design patterns.

  •  Design pattern focuses on low-level details of the application, not heigh level details, so it's safe to say that architecture pattern only focuses on heigh level details.
  • Architecture comes in the Designing phase and Design Patterns come in the Building phase.
  • An architectural pattern is like a blueprint and a design pattern is the actual implementation.
  • Architecture is base on which everything else adhere to and design pattern is a way to structure classes to solve common problems.
  • All Architecture is a design pattern but all design patterns can't be architecture. Like MVC can come under both. But singleton design pattern can't be an architecture pattern. MVC, MVVM all come under both.
Model-View-ViewModel (MVVM) is a structural design pattern that helps you to write standard loose coupled code. Your code is divided into model, view & view model.

Model

This is only your model, nothing much here, it's exactly the same model as in MVC. It is used by VM and updates whenever VM sends new updates.
Also known as the data layer. For example name. age, user, music, movie all of these are examples of data. View (ViewController)
User Interface & gets data from the view model. Labels, buttons, text fields, table view, etc are examples of views. Users can see, interact, input in views. It only performs things related to UI. View Model
Business Logic and returns data to view controller. It gets data from data source/provider and in our example, we are getting data from APIHandler class which provides JSON data from a URL. This means it receives information from VC handles all this information and sends it back to VC.





Choosing the right architecture pattern for your project Whenever we get a new project, what we have to think about is a lot of things, which is basically the first thing we think about. 

  • Project Requirements: What are the project requirements? What this project does, basically high level requirements.
  • Project complexity: considering the requirement. We calculate the complexity of what is the hidden complexity or known complexity of the project. 
  • Project Deadline: This is set by the client i.e. the client wants an application and wants the application to be done in 4-5 months.
  • Architectural Patterns for Project: Now, comes the architecture of the project. The architecture of the project is determined by the complexity of the project's requirements, that is, considering the requirements and complexity, we think that this architectural pattern is the most appropriate for the project.


When should I use MVVM

  • Don't use MVVM for small project.
  • Use MVVM for moderately complex application.
  • moderately complex- project that are between 4-6 months duration and require 4-10 team member.

Advantages of MVVM

  • Business logic is decoupled from Ul
  • Easy to maintain and test
  • Easy to reuse components
  • Loosely coupled architecture: MWM makes your application architecture as loosely coupled.
  • Internal implementation to be chnaged without affecting the others. 
  • You can write unit test cases for both the viewmodel and Model layer without the need to reference the View.


Let’s start in this projectwe'll be building an easy application using the MVVM design pattern. In most of our application, we've a view controller (UI) which must fetch data from the server(API) and wish to display it within the UI. we'll implement an equivalent behavior using the MVVM Pattern.

Project hierarchy looks like this:


Constent

First create a constant class for url.


//
//  Constant.swift
//  MVVM_Example
//
//  Created by Rathaur on 02/07/20.
//  Copyright © 2020 AppCodeZip. All rights reserved.
//

import Foundation

struct EndPoint {
    static let strUrl = "https://jsonplaceholder.typicode.com/posts"
}

Model

The model represents simple data. It only holds data and has nothing to try with any business logic. You would just say that this is a clear structure of knowledge that we expect from our API. Here i will crate the user model class.


//
//  User.swift
//  MVVM_Example
//
//  Created by Rathaur on 02/07/20.
//  Copyright © 2020 AppCodeZip. All rights reserved.
//

import Foundation


class User : Codable{
    var userId : Int?
    var id : Int?
    var title : String?
    var body : String?
}

ViewModel

ViewModel receives information from VC, handles all this information and sends it back to VC. it is the main component of this architecture pattern. This architecture more testable and removes complexity from the view.In View Model, we'll call our APIService class to fetch data from the server. Here i will crate the user UserViewModel class.

//
//  UserViewModel.swift
//  MVVM_Example
//
//  Created by Rathaur on 02/07/20.
//  Copyright © 2020 AppCodeZip. All rights reserved.
//

import Foundation

class UserViewModel{
    typealias completionBlock = ([User]) -> ()
    var apiHandler = APIHandler()
    var datasourceArray = [User]()

    
   func getDataFromAPIHandlerClass(url: String, completionBlock : @escaping completionBlock){
    
    apiHandler.getDataFromApi(withUrl: url) { [weak self] (arrUser) in
        self?.datasourceArray = arrUser
        completionBlock(arrUser)
    }
    }
    
    func getNumberOfRowsInSection() -> Int{
        
        return datasourceArray.count
    }
    
    func getUserAtIndex(index : Int) -> User{
        
        let user = datasourceArray[index]
        return user
    }
    
    func getCellData(index : Int) -> String{
        
        let user = self.getUserAtIndex(index: index)
        
        let userId = user.userId ?? 0
        let id = user.id ?? 0
//        let body = user.body ?? ""
        let title = user.title ?? ""
        let res = "UserId- \(userId)" + " " + "ID- \(id)" + " " + "Title- \(title)"
        return res
    }
    
    func getDetailCellData(index : Int) -> String {
         let user = self.getUserAtIndex(index: index)
        let body = user.body ?? ""
        let detailRes = "Body- \(body)"
        return detailRes
    }
    
}


API Handler

API Handler class is a simple class where we are fetching user data using URLSession class. you can use any networking model here to fetch data from your server.

//  APIHandler.swift
//  MVVM_Example
//
//  Created by Rathaur on 02/07/20.
//  Copyright © 2020 AppCodeZip. All rights reserved.
//

import Foundation

class APIHandler{
    
    typealias completionBlock = ([User]) -> ()
    
    func getDataFromApi(withUrl strUrl : String, completionBlock : @escaping completionBlock){
        
        if let unwrappedUrl = URL(string: strUrl){
            
            URLSession.shared.dataTask(with: unwrappedUrl, completionHandler: { (data, response, error) in
                
                if data != nil{
                    let jsonDecoder = JSONDecoder()
                    let userArray = try? jsonDecoder.decode([User].self, from: data!)
                    
                    if userArray != nil{
                        completionBlock(userArray!)

                    }else{
                        let aArray = [User]()
                        completionBlock(aArray)
                    }
                }else{
                    let aArray = [User]()
                    completionBlock(aArray)
                }
                
            }).resume()
        }
    }
        
}

View (ViewController)

User Interface & gets data from the view model. It only performs things related to UI.


//
//  ViewController.swift
//  MVVM_Example
//
//  Created by Rathaur on 02/07/20.
//  Copyright © 2020 AppCodeZip. All rights reserved.
//

import UIKit

class ViewController: UIViewController{
    
    @IBOutlet weak var tblView: UITableView!
    var viewModel = UserViewModel()

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        viewModel.getDataFromAPIHandlerClass(url: EndPoint.strUrl) { (_) in
            
            DispatchQueue.main.async { [weak self] in
                self?.tblView.reloadData()
            }
        }
    }
}

extension ViewController : UITableViewDataSource, UITableViewDelegate {
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 90.0
    }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return viewModel.getNumberOfRowsInSection()
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell")
        
        cell?.textLabel?.text = viewModel.getCellData(index: indexPath.row)
        cell?.detailTextLabel?.text = viewModel.getDetailCellData(index: indexPath.row)
        return cell!
    }
    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {

            if(indexPath.row % 2 == 0) {
                cell.backgroundColor = UIColor.red.withAlphaComponent(0.05)
            } else {
                cell.backgroundColor = UIColor.white
            }
    }
}


Thanks for reading!!


Similar solutions you may also like...

Post a Comment

0 Comments