Combine example with URLSession and assign value to a labels text
Combine example with URLSession and assign value to a labels text

Combine Getting Started Guide

Learn Swift’s Combine framework through examples and sample code. A brief intro to publishers, operators, and subscribers.

What is Combine?

In short, Combine enables subscribing to output or values over time with a declarative API. For example, if you’re making a network request to fetch JSON.

Create a new playground and paste the code in to test it out!

Notice how Combine is built into url session, you’ll see it throughout Apple’s API ecosystem i.e notification center, timers.

  1. Create a new data task publisher to fetch data at a URL.
  2. Map on the response and get the Data via keypaths.
  3. Decode the response into a dictionary.
  4. CompactMap on the dictionary to the property results.
  5. Replace errors with an empty array (throwing away the error).
  6. Create a new publisher on the main queue.
  7. Assign the subscription input to the text property on UILable.
  8. Cancel the subscription and release it from memory.

We’ve achieved a composable chain of operations in a URL as an input and delivered the output to subscribers in a UI consumable model.

Another way to remember this pipeline is with an analogy using Netflix. Netflix publishes movies and tv shows to their servers. Then some operations are run to make them appear in an app. Finally, you subscribe to Netflix to access the movies, and when you no longer want to use Netflix, you cancel your subscription.

An analogy of Combine concepts to Netflix
An analogy of Combine concepts to Netflix
An analogy of Combine concepts to Netflix

Combine has four main parts, publishers, operators, subscribers, and cancellable. Get familiar with these four terms because they are the foundation of the framework. Here is a cheatsheet of the terminology.

CHEATSHEETPublishers
* Outputs values over time, allows 0 or more values or errors
to be emitted.
* PassthroughSubject, CurrentValueSubject, @Published, Just
Operators
* Input and output same or new publisher
* map, tryMap, compactMap, filter, decode, scan, receive(on:), ...
Subscriber
* Inputs values and a completion/error
* sink(_:), assign(on:to:), onReceive(_:perform:)
Cancellable
* Cancels the subscription and releases memory
* store(in: &cancellables) // Set<AnyCancellable>

Publishers

Publishers output 0 or more values once a subscriber has subscribed. In addition to ones built into Apple's APIs, you can create your own. The common publishers used are PassThroughSubject, CurrentValueSubject, and @Published.

PassthroughSubject

A PassthroughSubject sends a stream of values to subscribers. Under the hood, you can see that it is generic over some Output and Error, then returns a cancellable (more on that later).

Notice in the example above the second generic parameter Never, meaning it will never emit an error. However, if we want to handle an error, it make it a Error type.

CurrentValueSubject

A CurrentValueSubjects is similar to a PassthroughSubjects but can be initialized with a default value. Another difference is we can access the value property on it to fetch the publisher's current value at that moment in time.

In the example above, we are simulating the search bar UX, and anytime the user types on the keyboard, a new string is published, and an API request is made.

Published

Published is a property wrapper that can only be used in classes. Unlike the subjects above, Published they can only send new values on assignment, not via a send() method. To subscribe to a Published property, you can use the $ operator. Otherwise, you will get a compiler error.

⚠️ Publishing occurs in the property’s willSet block, meaning subscribers receive the new value before it’s actually set on the property — Apple Docs

Here are a few others from the Apple Combine documentation that I haven’t had to use too often, but they may be helpful in a particular scenario.

class FutureA publisher that eventually produces a single value and then finishes or fails.struct JustA publisher that emits an output to each subscriber just once, and then finishes.struct EmptyA publisher that never publishes any values, and optionally finishes immediately.struct FailA publisher that immediately terminates with the specified error.

Operators

Operators take in some input and return the same or new publisher while deterministically defining an order or chain of operations. You can combine many operators because they are extremely decoupled.

There are too many operators to go over, and you’ve already seen a few in action above. For a full list, visit this free book resource here.

I do want to go over the difference between subscribe(on:) and receive(on:). It’s easy to get these two mixed up or not know the right one to use.

  1. subscribe(on:) changes the queue for the operations and subscription to the background.
  2. receive(on:) changes the queue for the downstream subscription back to the main queue.
Print output of the example above

⚠️ Notice the breakpoint(receiveOutput:) and print() operators. You can use these to easily debug errors or inspect what is happening in publishers.

Subscribers

Subscribers receive input from publishers after any operators have transformed it. In addition to receiving the output value, subscribers also can receive a completion or error, meaning the publisher has stopped emitting values. There are two ways to subscribe to a publisher in Combine.

Sink

Sink is an operator that subscribes to a publisher. Depending on your publisher, the signature can vary. For example, if the publisher and give you an Errorthe signature of sink will require adding a completion block where you can handle it. Otherwise, you can use the short-hand syntax below.

Assign

We’ve seen an example of assign(to:on:)above already. In short, it assigns the output value from the publisher to a keypath property (kvo compliant) on an NSObject. It has an alternative initializer assign(to:) that can be used to assign the subscription to another publisher.

You’ll usually need to use one or the other, but keep this in mind if you need it.

OnReceive

SwiftUI has a built-in modifier that acts as a subscriber. It takes a publisher as the first argument and gives you a block that is called when a value is published.

Cancellable

In short, a Cancellable cancels the subscription and releases the publisher from memory. Cancellable is a protocol that every publisher, operator, and subscriber conform to and return. AnyCancellable is the concrete type used to discard the subscription from memory or bind to the subscription's lifespan.

⚠️ Subscribers conform to Cancellable, meaning they have a function called cancel(). Don’t call it on the subscription directly as it doesn’t discard it from memory, use the approaches below.

AnyCancellable

Important

Anytime you are capturing self in a subscription, like sink, be sure to do it weakly ([weak self]). Capturing self in a subscription block, can prevent the cancellable from removing the reference on deinit.

Note you can’t mutate a property in a SwiftUI struct without using state. So storing or assigning a publisher to a cancellable will cause a compiler error. It’s best to move any publishers out of SwiftUI views and into a view model where the view model can manage the publisher lifecycle. Then use the property wrapper @ObservedObject in the view and update the UI as properties on the view model change.

Conclusion

As you can see, Combine is a powerful framework. We’ve gone over the major parts of it, like publishers, operators, and subscribers. With these new concepts, you are more than equipped to start it. The best part of using Combine is the APIs don’t need to be maintained by you, and the code is extremely composable and reusable. When testing it, you only need to worry about the input and output, not the complex stuff in the middle.

Few resources if you want to go more in-depth (no aff):

If you enjoyed this check my Patreon or YouTube for tutorials and posts I make around Swift and swe’ing in general 😎

iOS Software Engineer ⚡️ Creator

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store