Introducing Combine Framework

Lets deep dive on Publisher, Subscriber, Operators and Subjects

Functional Reactive Programming
Apple’s Combine framework introduced during WWDC 2019, it allows you to write functional reactive code by providing a declarative Swift API. In other words, it implements FRP model similar to that of RX by RXSwift and ReactiveSwift. The combine is useful in applications that have data that changes over time. For example, user interface events, network calls and other asynchronous data.

Combine = Publisher + Operators + Subscriber

In this article we are going to focus on the main concepts of Combine

  • Publisher — Sends sequence of values over time to one or more subscribers
  • Operators — Its a special methods that returns another Publiser
  • Subscriber — It receives value from the Publisher
  • Subjects — Publisher that insert values from outside into the stream

Publisher and Subscriber

The Combine publisher transmits a single value or multiple values or no value at all. The Foundation framework and SwiftUI provides additional convenience publishers like; dataTaskPublisher, Timer, NotificationCenter, Result and @Published, @ObservedObject property wrappers to supports its declarative mechanisms.

Image for post
Image for post
Networking Publisher

In the networking layer, once we create a publisher, we attached a subscription to it by using the sink API, which has a closure with a completion handler and receiving value. This publisher always returns an object that conforms to Cancellable protocol which acts as a new subscription. The subscriptions are canceled when the object that is holding on to AnyCancellable is deallocated. You can also manually cancel it by calling cancel().

Image for post
Image for post
NotificationCenter Publisher

NotificationCenter is also one of the build-in publisher, where we can subscribe to the notification by using publisher.

Image for post
Image for post
Timer Publisher

You can use combine for Timer to get periodic time updates, it can also be trigger automatically or manually.

Image for post
Image for post
Property Wrapper Publisher

@Published is a property wrapper, which can attach a publisher to a single variable (i.e isSubmitEnabled). In the above example, the submit button should be enabled only if the terms switch is checked. So the $ is added as a prefix to the variable similar to binding the object and .assign is subscribe to value change. Any change to isSubmitEnabled value will bounds to submit button to assign the property .isEnabled on the main queue as we’re working with UI.

Subjects

The Subjects can send a value between Publisher and Subscriber. There are two types of build-in subjects,

  • PassthroughSubject — A subject that broadcasts elements to downstream subscribers.
  • CurrentValueSubject — It holds the current value when a subscriber is triggered. Creates a current value subject with the given initial value.
Image for post
Image for post
Subjects

Operators
Combine ships with multiple operators which transform the publishers in different ways. It used to build reactive chains or pipelines that our data can flow through.

Image for post
Image for post
Operators
let numbers = (1...100).publisher
numbers.dropFirst(50)
.prefix(20)
.filter { $0 % 2 == 0 }
.sink {print($0)}

The above code is used to filtering the even numbers from a range of 50–70. So the first step is to use dropFirst operator to skip the first 50 values emitted by the upstream publisher. Then take the next 20 values after those first 50 values using prefix and filter only the even numbers.

Image for post
Image for post
dataTaskPublisher with operators

There is a chain of operators to return AnyPublisher<Weather, Error>. .print() is used to log the lifecycle of Combine flow. .map is to get the response data and .decode it to transform the data into WeatherResponse object which conforms to decodable protocol. Now I’m going to optimise the decode operator by extending the JSONDecoder and Publisher.

Image for post
Image for post
Extension of JSONDecoder and Publisher
Image for post
Image for post
Optimising the decode operator

The sink operator is used to handle the result with two closures — one for handling each output value, and one for handling completion events. It is a bit inconvenient so it’s always better to have a Result value to access success and failure. Now its time to create a custom operator to change the result type.

Image for post
Image for post
Extension of publisher to create custom operator
Image for post
Image for post
Handle Result value with convertToResult() operator
Image for post
Image for post
Sink with Result value as closure

Conclusion
Combine is an exciting and powerful framework with a ton of different APIs and capabilities. By adopting Combine, you’ll make your code easier to read and maintain, by centralizing your event-processing code and eliminating troublesome techniques like nested closures and convention-based callbacks. You can find a sample app with combine framework on Github.

Written by

Mobile Application Developer (iOS, Flutter)

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