MVVM in SwiftUI

MVVM in SwiftUI
MVVM in SwiftUI. Apple announced SwiftUI at WWDC 2019. SwiftUI is a declarative framework for building applications for Apple devices.

MVVM in SwiftUI

Apple announced SwiftUI at WWDC 2019. SwiftUI is a declarative framework for building applications for Apple devices. This means that instead of using Storyboards or programmatically generating your interface, you can use the simplicity of the SwiftUI framework.

SwiftUI does not follow MVC architecture. This means when you create a brand new application in Xcode 11 and enable SwiftUI, it does not create any controllers. This does not mean that you can’t use MVC design pattern with SwiftUI, it simply means maybe a different pattern (MVVM) can better suite your needs.

In this article, I will create a complete News App using SwiftUI and MVVM design pattern. This article is part of my new Udemy course on SwiftUI. You can check out the course below:

Implementation

We will be consuming latest headlines from NewsAPI.org website. It is recommended that you register with NewsAPI.org website to obtain an API Key, which will be mandatory for making any requests to the service.

Webservice and Models

Before jumping into SwiftUI, let’s go ahead and create our Webservice which will be responsible for retrieving the latest news from the NewsAPI. The Webservice is implemented below:

class Webservice {
    
    func loadTopHeadlines(url: URL, completion: @escaping ([Article]?) -> ()) {
        
        URLSession.shared.dataTask(with: url) { data, response, error in
            
            guard let data = data, error == nil else {
                completion(nil)
                return
            }
            
            let response = try? JSONDecoder().decode(NewsResponse.self, from: data)
            if let response = response {
                DispatchQueue.main.async {
                    completion(response.articles)
                }
            }
            
            
        }.resume()
        
    }
    
}

.swift

The loadTopHeadlines function retrieves all the articles and populate the Article model. The Article and NewsResponse model are implemented below:

import Foundation

struct NewsResponse: Codable {
    let articles: [Article]
}

struct Article: Codable {
    let title: String
    let description: String?
}

.swift

View Models

The models will get the data from the webservice and then hand it over the View Models which will be responsible for displaying it on the screen. The ArticleViewModel represents a single article which will be displayed in a cell contained in the List control. The implementation of ArticleViewModel is shown below:

class ArticleViewModel: Identifiable {
    
    let id = UUID()
    
    let article: Article
    
    init(article: Article) {
        self.article = article
    }
    
    var title: String {
        return self.article.title
    }
    
    var description: String {
        return self.article.description ?? ""
    }
    
    
}

.swift

The ArticleViewModel conforms to the Identifiable protocol since it has to supply data to the List. The List uses the id property to make sure that the contents of the list are unique.

Next, we will implement ArticleListViewModel. This view model is responsible for reflecting the contents of the entire screen. ArticleListViewModel will also utilize the Webservice and retrieve all recent articles.

class ArticleListViewModel: BindableObject {
    
    let didChange = PassthroughSubject<ArticleListViewModel,Never>()
    
    init() {
        fetchTopHeadlines()
    }
    
    var articles = [ArticleViewModel]() {
        didSet {
            didChange.send(self)
        }
    }
    
    private func fetchTopHeadlines() {
        
        guard let url = URL(string: "https://newsapi.org/v2/top-headlines?country=us&apiKey=InsertYourAPIKeyHere") else {
            fatalError("URL is not correct!")
        }
        
        Webservice().loadTopHeadlines(url: url) { articles in
            
            if let articles = articles {
                self.articles = articles.map(ArticleViewModel.init)
            }
            
        }
        
    }
    
}

.swift

There are couple of interesting things going on in ArticleListViewModel. First, you will notice that it conforms to the BindableObject protocol. This means that it can publish events to the subscribers and can be binded to views on the screen. The only requirement of BindableObject is to implement the didChange event. The didChange event will notify the subscribers of the new data that is available.

In the fetchTopHeadlines function we make a Webservice request to retrieve all the news articles. Once, we receive all the articles we assign to the articles property which has a didSet. This fires the didChange passing in the self which in this case is ArticleListViewModel.

Now, the only thing left to do is to make sure that the articles are displayed on the screen. Let’s see how SwiftUI can make this super easy!

SwiftUI

The declarative style provided by SwiftUI makes building the interface very easy. This is the complete code for SwiftUI (ContentView.swift).

struct ContentView : View {
    
    @ObjectBinding var model = ArticleListViewModel()
    
    var body: some View {
        List(model.articles) { article in
            
            VStack(alignment: .leading) {
            
            Text(article.title)
                .lineLimit(nil)
            
            Text(article.description)
                .foregroundColor(.secondary)
                .lineLimit(nil)
                
            }
            
        }
    }
}

.swift

The first thing to note over here is that the model is marked with @ObjectBinding. This means when the model is eventually set, after the asynchronous call, it will render the screen again by executing the body property. If you replace the @ObjectBinding with @State then will still work as expected. But the purpose of @State is different from @ObjectBinding, which will be explain the future. The screenshot below shows the app in action.

I really hope you liked the article. If you want to support my work then check out my latest course on SwiftUI below.

Flutter & Dart Development For Building iOS and Android Apps

The Complete Flutter App Development Course for Android, iOS

The Complete Flutter and Firebase Developer Course

Dart 2 Complete Bootcamp - Go Hero from Zero in Dart Flutter

Flutter - Firebase - CRUD - Build 2 Apps super easy!

Dart Masterclass Programming Course: iOS/Android Bible

Suggest:

Top 4 Programming Languages to Learn in 2019 to Get a Job

Ecommerce Furniture App UI Design - Flutter UI - Speed Code

Top 4 Programming Languages to Learn In 2019

Build a NOTES APP with Vue JS and Nhost using GraphQL & Tailwind CSS

Build a Real Time Chat App With Node.js

What To Learn To Become a Python Backend Developer