Combine Framework In SwiftUI: The Publishers

Part 2

Bitsandbytesch
4 min readMay 28, 2024
SwiftUI Combine Publishers

What are Publishers?

In the context of Combine, a publisher is a type that can deliver a sequence of values over time.

The basic concept behind a publisher is that it produces values that subscribers can receive and react to. This mechanism is fundamental to reactive programming, where you react to changes or events as they occur, rather than polling or manually updating the state.

Key Publishers in Combine:

1. Just

2. Future

3. PassthroughSubject

4. CurrentValueSubject

5. Custom Publishers

1. Just:

A publisher that emits a single value and then finishes.

let justPublisher = Just("Hello, SwiftUI!")

We’ll create a simple SwiftUI view that uses a Just publisher to display a static message. This can be particularly useful for initial setups or displaying static information that doesn’t change.

import SwiftUI
import Combine

class JustPublisherViewModel: ObservableObject {
@Published var message: String = ""
var justmessage: String = "Follow this"

private var cancellable: AnyCancellable?

init() {
setupJustPublisher()
}

private func setupJustPublisher() {
let justPublisher = Just(justmessage)

cancellable = justPublisher
.sink { [weak self] value in
self?.message = value
}
}
}

In this ViewModel, we create a Just publisher that emits a single value (“Follow this”). The sink operator subscribes to the publisher and updates the message property.

You can find the codes in my GitHub repository. Link At the End of this Publish.

2. Future:

A publisher that eventually produces a single value or error. Future publisher is useful for handling asynchronous operations that complete with either a single value or an error, such as fetching data from a network.

let futurePublisher = Future<String, Error> { promise in
// Asynchronous operation
DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
promise(.success("Future value"))
}
}

Future publisher is useful for handling asynchronous operations that complete with either a single value or an error, such as fetching data from a network.

class FuturePublisherViewModel: ObservableObject {
@Published var message: String = "Loading..."

private var cancellable: AnyCancellable?

init() {
fetchData()
}

func fetchData() {
cancellable = fetchMessage()
.sink(receiveCompletion: { completion in
switch completion {
case .finished:
break
case .failure(let error):
self.message = "Error: \(error.localizedDescription)"
}
}, receiveValue: { value in
self.message = value
})
}

private func fetchMessage() -> Future<String, Error> {
return Future { promise in
DispatchQueue.global().asyncAfter(deadline: .now() + 2) {
let success = Bool.random()
if success {
promise(.success("If you download this give this a star in github!!!"))
} else {
promise(.failure(NSError(domain: "FetchError", code: 1, userInfo: [NSLocalizedDescriptionKey: "Failed"])))
}
}
}
}
}

In this ViewModel, we define a Future publisher in the fetchMessage method, which simulates a network request. The Future publisher either completes with a success message or an error after a delay.

You can find the codes in my GitHub repository. Link At the End of this Publish.

Isn’t it similar to Flutter’s Dart Async ‘Future’ ??? 🤐

Moving on..

3. PassthroughSubject:

A publisher that you can manually send values to, commonly used for bridging imperative code with Combine.

let passthroughSubject = PassthroughSubject<String, Never>()
passthroughSubject.send("value")

The SwiftUI view that uses a PassthroughSubject to handle button taps and update a label with the number of times the button has been pressed.

import SwiftUI
import Combine

class PassthroughSubjectViewModel: ObservableObject {
@Published var tapCount: Int = 0

private var cancellable: AnyCancellable?
private let buttonTapSubject = PassthroughSubject<Void, Never>()

init() {
cancellable = buttonTapSubject
.sink { [weak self] in
self?.tapCount += 1
}
}

func buttonTapped() {
buttonTapSubject.send()
}
}

In this ViewModel, we define a PassthroughSubject that sends Void values whenever the button is tapped. The sink operator subscribes to the subject and increments the tapCount property each time a value is sent.

You can find the codes in my GitHub repository. Link At the End of this Publish.

Typical Swift Closure ? 😀 Not Really..

Moving On..

4. CurrentValueSubject:

It is similar to PassthroughSubject, but it maintains a current value that new subscribers receive upon subscription.

let currentValueSubject = CurrentValueSubject<String, Never>("Initial value")

🤔 Similar ? “State” and “Initial value” — found the difference .. 😎

import SwiftUI
import Combine

class CurrentValueSubjectViewModel: ObservableObject {
@Published var currentValue: String = ""

private var cancellable: AnyCancellable?
private let currentValueSubject = CurrentValueSubject<String, Never>("0")

init() {
cancellable = currentValueSubject
.sink { [weak self] value in
self?.currentValue = value
}
}

func updateValue(newValue: String) {
currentValueSubject.send(newValue)
}
}

In this ViewModel, we define a CurrentValueSubject that holds a String value. The sink operator subscribes to the subject and updates the currentValue property each time a new value is sent.

PassthroughSubject vs CurrentValueSubject

Both PassthroughSubject and CurrentValueSubject conform to Subject Protocol and therefore we can call send on them to Push the values.

PassthroughSubject Usecase: Where the current state is not needed, like button taps, notifications

CurrentValueSubject Usecase: Where we need to keep track of the current state and provide it to new subscribers, like user settings, form inputs.

Final Thoughts:

Whether you’re handling user input, binding data, or fetching network resources, publishers provide the flexibility and control needed to build sophisticated SwiftUI apps.

Upcoming- In Part 3 we will further deep dive in to Publishers. We will create Custom Publishers and go through the URLSession Publisher and Property Publishers.

Write a Beautiful Code !!

Github — https://github.com/SaurabhBisht?tab=repositories

Instagram: https://www.instagram.com/bitsandbytesch/

Youtube: https://www.youtube.com/@BitsAndBytesCH/videos

--

--

Bitsandbytesch

Join our channel for a comprehensive exploration of Industry Tips, Experts interviews, code languages and system design concepts. Follow now :)