SwiftUI Discovery - Part 2

Last week I was taking a first look at SwiftUI and was amazed by its potential (see SwiftUI Discovery - Part 1).

This week I will explain simply how to integrate a Data Flow into SwiftUI, mainly, how to update the UI from an external source of data such as an API.

As with any new technology, documentation and ressources are scarce to find the right answers to everyone’s questions. My first understanding is that SwiftUI data flow rest heavily on Combine, the new reactive framework by Apple.

The good news is that they made Combine much simpler to use than its older counterpart RxSwift. Which keeps SwiftUI usable by new developers (something RxSwift clearly doesn’t do) and yet provide the full power of a reactive framework.

import SwiftUI
import Combine

final class FooStore: ObservableObject {
	private let apiService = ApiService()
	
	@Published var bar = [Bar]()
	
	func refresh() {
		apiService.fetchBar { [weak self] result in
			switch result {
			case .success(let bar):
				self?.bar = bar
			case .failure(_):
				break // Do nothing
			}
		}
	}
}

struct FooList: View {
	@ObservedObject var fooStore: FooStore
	
	var body: some View {
		NavigationView {
			List(fooStore.bar, id: \.title) { bar in
				Text(bar.title)
			}
			.navigationBarTitle("Foo list")
		}
		.onAppear(perform: fooStore.refresh)
	}
}

On our example, you can see on line 4 that we declare an ObservableObject. As the observable object depends on SwiftUI, you would likely want it to sit outside your model layer, preferably as a ModelView in MVVM (see Back to the basics of MVVM on iOS), so you keep your model layer neutral.

On line 22 we bind the FooStore to our view, using @ObservedObject decorator, that’s all we need to magically bind our two objects together. Powerful.

Tancrede Chazallet