MVVM with SwiftUI and Combine

June 11, 20194 min read#swiftui, #combine, #architecture, #mvvm

Before WWDC 2019

Apple has always advertised MVC as the preferred architecture to develop iOS apps. So the community comes up with different alternative architectures to solve the “big view controllers” problem. MVVM is one of the most popular architecture used by iOS developers. Before WWDC 2019, most of MVVM implementations use some popular reactive framework such as RxSwift, ReactiveSwift or ReactiveKit along with their UI binding counterparts such as RxCocoa, ReactiveCocoa or Bond.

After WWDC 2019

In WWDC 2019, Apple has introduced two awesome frameworks which replace the above frameworks to provide reactive programming and UI bindings. From now on, developers can implement MVVM architecture for their apps using only native frameworks which provide many benefit such as stability, binary app size and consistent APIs etc…

Apple seems also to go away from MVC and adopt MVVM as the default architecture for apps development.


With SwiftUI, you don’t have to decide if you want to use visual tools or writting code to design, you can have both at the same time.

Some WWDC videos related to this topic:

MVVM using Swift and Combine

I’ve created a simple project to demonstrate how we can use those native frameworks to implement MVVM architecture for iOS apps. The code is here on github:

This project demonstrates how to implement MVVM using SwiftUI and Combine to search and display images from There are also some tests to demonstrate the testability of the implementation.

The View is written using SwiftUI framework. Each View has its own ViewModel which is responsible to call a Service to fetch data DataModel from the remote server:

// View Model
func search(withTerm term: String) {

    self.isActive = true

    let dataUpdater = AnySubscriber<ImageListModel, Error>(
        receiveValue: { [weak self] imageListModel -> Subscribers.Demand in
            self?.images = imageListModel.hits
            return .unlimited
        receiveCompletion: { [weak self] completion in
            if case let .failure(error) = completion {
                self?.images = []
            self?.isActive = false

    pixaBayService.fetch(searchTerm: term).subscribe(dataUpdater)

In View, ViewModel is declared as ObjectBinding to provide binding functionality, so that the View gets informed when ViewModel gets new data from the Service:

@ObjectBinding var viewModel = ImageListViewModel(pixaBayService: PixaBayService())

The Service uses Combine, specifically Future to return data from an asynchronous call:

func fetch(searchTerm: String) -> Publishers.Future<ImageListModel, Error> {
    let urlString = "\(searchTerm)&image_type=photo&pretty=true"
    let url = URL(string: urlString)!

    return Publishers.Future { resolver in

        URLSession.shared.dataTask(with: url) { data, _, error in
            guard error == nil else {
                return resolver(Result.failure(error!))

            guard let data = data else {
                return resolver(Result.failure(ServiceNetworkError.noData))

            do {
                let decoder = JSONDecoder()
                let imageData = try decoder.decode(ImageListModel.self, from: data)
                return resolver(Result.success(imageData))
            } catch {
                return resolver(Result.failure(error))


SwiftUI and Combine bring great foundations to build iOS apps with MVVM architecture. The best benifit is that you don’t have to rely on 3rd-party frameworks for your implementations. Native frameworks are always the best choices for awesome apps.

The code is open-sourced on Github


Quick Drop logo

Profile picture

Personal blog by An Tran. I'm focusing on creating useful apps.
#Swift #Kotlin #Mobile #MachineLearning #Minimalist

© An Tran - 2024