SwiftUI + Combine Framework

Shashidhar Jagatap
4 min readDec 25, 2023

--

Combine Framework Basics

The Combine framework, introduced by Apple, enables declarative Swift code for handling asynchronous and event-based programming using reactive principles. It integrates seamlessly with SwiftUI and provides a unified approach to handle asynchronous events and data streams.

Fundamental Concepts in Combine:

Publishers and Subscribers:

  • Publisher: Represents a sequence of values over time. It can emit elements, errors, and a completion signal.
  • Subscriber: Listens to a publisher, receives values emitted by the publisher, and can react to those values.

Operators:

  • Combine provides numerous operators (map, filter, flatMap, etc.) that allow transformation, filtering, and combination of values emitted by publishers.

Operators and Pipelines:

  • Publishers can be connected to subscribers via operators to create a pipeline. Data flows through this pipeline from the publisher to the subscriber, potentially undergoing transformation along the way.

Schedulers:

  • Schedulers are responsible for determining the execution context in which code associated with a publisher should run (e.g., main thread, background queue).

Internal Architecture and How It Works:

Publisher:

  • A publisher emits values, errors, and a completion signal (.finished or .failure).
  • It conforms to the Publisher protocol, which defines methods like subscribe, receive(subscriber:), and receive(subscription:).

Subscriber:

  • A subscriber subscribes to a publisher using the subscribe(_:) method.
  • It conforms to the Subscriber protocol, which defines methods like receive(subscription:), receive(_:Input), receive(completion:).

Subscription:

  • When a subscriber subscribes to a publisher, it receives a Subscription object.
  • Subscription manages the interaction between a publisher and a subscriber by controlling the demand for values and handling cancellations.

How Reactive Flow Works:

  • Publishers emit values and send them downstream to subscribers.
  • Subscribers can receive these values, apply transformations or filtering using operators, and perform further actions accordingly.
  • Subscribers can request more values using demand from the publisher when needed. This demand-driven approach helps manage backpressure.

Combine’s Functional Approach:

  • Combine uses functional programming concepts (map, filter, etc.) to manipulate data streams, creating a pipeline that transforms and processes values.

Schedulers for Asynchronous Operations:

  • Combine leverages schedulers to control when and where various parts of a subscription occur, allowing work to be executed on different queues or threads.

Summary:

Combine brings reactive programming principles to Swift, allowing developers to handle asynchronous events, data streams, and state changes in a declarative and composable manner. It promotes a functional and reactive paradigm by providing publishers, subscribers, operators, and schedulers that work together to manage and process asynchronous data streams efficiently. The key to working effectively with Combine is understanding publishers, subscribers, the flow of data, and the various operators available to transform and handle data streams.

SwiftUI implementation with Combine

The Combine framework in Swift provides a declarative Swift API for processing values over time. When combined with SwiftUI, it enables reactive and data-driven user interfaces. Below is an example of how you can use Combine with SwiftUI to perform networking and update the UI based on the fetched data.

This example demonstrates fetching data from an API and displaying it in a SwiftUI view. We’ll use URLSession to perform a network request and Combine to handle the asynchronous data flow.

Model

import SwiftUI
import Combine

// Model for representing fetched data
struct Post: Decodable {
let id: Int
let title: String
let body: String
}

View Model

// ViewModel to handle networking and data flow
class PostViewModel: ObservableObject {
// Published property to notify view of data changes
@Published var posts: [Post] = []

private var cancellable: AnyCancellable?

init() {
fetchPosts()
}

func fetchPosts() {
// Replace with your API endpoint URL
let urlString = "https://jsonplaceholder.typicode.com/posts"

guard let url = URL(string: urlString) else { return }

// Create a URLSession data task publisher
cancellable = URLSession.shared.dataTaskPublisher(for: url)
.map(\.data) // Extract data from response
.decode(type: [Post].self, decoder: JSONDecoder()) // Decode JSON into array of Posts
.replaceError(with: []) // Replace errors with an empty array
.receive(on: DispatchQueue.main) // Receive on main queue to update UI
.sink(receiveValue: { [weak self] fetchedPosts in
self?.posts = fetchedPosts // Update posts with fetched data
})
}
}

SwiftUI View

// SwiftUI ContentView displaying fetched data
struct ContentView: View {
@ObservedObject var viewModel = PostViewModel()

var body: some View {
NavigationView {
List(viewModel.posts, id: \.id) { post in
VStack(alignment: .leading) {
Text(post.title)
.font(.headline)
Text(post.body)
.font(.body)
.foregroundColor(.gray)
}
}
.navigationTitle("Posts")
}
}
}

// Preview
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}

Explanation:

  1. Post: A simple Post model struct to represent the data fetched from the API.
  2. PostViewModel: An ObservableObject that fetches data using Combine. It has a @Published property posts that notifies the view whenever it changes.
  3. fetchPosts(): Method in PostViewModel that performs a network request using URLSession data task publisher.
  4. ContentView: SwiftUI view that observes changes in PostViewModel and displays fetched data in a List.

This example demonstrates a simple use case of Combine with SwiftUI to fetch and display data. It’s a starting point for understanding how to integrate Combine’s reactive data flow with SwiftUI. Adjust the Post model, API endpoint, or UI components as needed for your specific use case.

--

--

Shashidhar Jagatap

iOS Developer | Objective C | Swift | SwiftUI | UIKit | Combine | Crafting Engaging Mobile Experiences |