Using PassthroughSubject in SwiftUI with Combine

|

In SwiftUI, Combine provides publishers like PassthroughSubject to help bridge imperative actions to reactive SwiftUI interfaces. PassthroughSubject is a publisher that you can trigger manually to emit values to its subscribers. This is particularly useful in scenarios where you want to update the UI based on user actions or external events.

What is PassthroughSubject?

Unlike other publishers, PassthroughSubject does not emit values automatically; instead, it waits until you send a value explicitly with .send(). This makes it a perfect tool for managing events in a reactive way, as you can control when and what data gets sent.

In this article, we’ll build a SwiftUI view that demonstrates how to use PassthroughSubject to handle a user action and update the UI.

Example SwiftUI View with PassthroughSubject

Below is a SwiftUI view that uses PassthroughSubject to publish messages each time a button is pressed.

import SwiftUI
import Combine

struct PassthroughSubjectView: View {
    // State variable to display the message in the view
    @State private var message: String = "Waiting for update..."
    
    // PassthroughSubject to publish new messages
    private let messageSubject = PassthroughSubject<String, Never>()
    
    // AnyCancellable to store the subscription
    @State private var cancellable: AnyCancellable?
    
    var body: some View {
        VStack(spacing: 20) {
            Text("PassthroughSubject Example")
                .font(.headline)
                .padding()
            
            Text(message) // Display the current message
                .font(.title)
                .padding()
            
            Button("Send New Message") {
                // Trigger the PassthroughSubject with a new message
                messageSubject.send("Hello from PassthroughSubject!")
            }
            .padding()
            .background(Color.blue)
            .foregroundColor(.white)
            .cornerRadius(8)
        }
        .onAppear {
            // Subscribe to the subject when the view appears
            cancellable = messageSubject
                .sink { newMessage in
                    message = newMessage
                }
        }
        .onDisappear {
            // Cancel the subscription when the view disappears
            cancellable?.cancel()
        }
    }
}

struct PassthroughSubjectView_Previews: PreviewProvider {
    static var previews: some View {
        PassthroughSubjectView()
    }
}

Explanation of the Code

  1. State Variable:
    • @State private var message: This variable holds the message displayed in the view. It starts with a placeholder and is updated whenever the PassthroughSubject publishes a new value.
  2. PassthroughSubject:
    • private let messageSubject = PassthroughSubject<String, Never>(): This PassthroughSubject emits String values and has a Never failure type, meaning it doesn’t produce errors. It’s used here to publish messages that will be displayed in the UI.
  3. Button to Trigger the Subject:
    • The button labeled Send New Message sends a new message ("Hello from PassthroughSubject!") whenever it’s pressed. This action triggers the PassthroughSubject, passing the message to all subscribers.
  4. Subscriber Setup in onAppear:
    • The .onAppear modifier subscribes to messageSubject using .sink. Each time the subject publishes a new message, sink updates message, which then refreshes the SwiftUI view to display the updated text.
  5. Cleaning Up the Subscription:
    • The .onDisappear modifier cancels the subscription when the view disappears, a good practice for preventing memory leaks or unintended updates when the view is no longer in use.

Summary

This example illustrates how PassthroughSubject can act as a bridge between imperative and reactive code in SwiftUI. By manually sending values with .send(), you have full control over when events are published. Whenever the button is pressed, PassthroughSubject publishes a new value, which updates the message state variable and refreshes the UI. This pattern is particularly useful when you need to trigger events manually but still want to leverage the power of reactive data flow in SwiftUI.

This approach scales well for scenarios where data changes based on user actions or external events, making PassthroughSubject a valuable tool in your SwiftUI toolkit.

Leave a Reply

Your email address will not be published. Required fields are marked *