Combine framework in action
Creating a simple GitHub repositories search app with Apple’s new Combine Framework.
This year WWDC introduced a lot of new stuff to the Apple development world. In addition to SwiftUI, Dark Mode and Diffable CollectionView DataSources, we have the new Combine framework. Combine is a Functional Reactive Programming framework which provides a collection of abstractions with the declarative syntax for dealing with your asynchronous and synchronous state changes.
I want to show you the Combine framework in action by creating a simple GitHub repositories search app. Let’s dive into the example project we will build today. As always, I start with the model layer.
In the example above we have a GithubService class which uses URLSession to fetch data over the network. We use the new URLSession method called dataTaskPublisher. It returns the Publisher for a network operation, which we are going to execute. Publisher is a key concept of the Combine framework. We use it to publish state changes like a response or error of our network call. Publisher is a protocol with two associated types; the first one describes a type of state, and the second one is a type of error which can occur.
As you can see in the GithubService class among the Publisher, we use a bunch of methods like map, decode, etc. In terms of the Combine framework, we call them Operators. Combine provides a lot of Operators, and we can use them to mutate the output of Publisher. URLSession’s Publisher uses a tuple of Data and URLResponse as the output, and this is where we can use the Map operator to map the current output to another type. All we need is a data response of network request, which is why in map closure we return data. Combine’s Map operator works pretty similar to Sequence’s map function.
Another exciting operator here is Decode. By using the Decode operator, we can easily deserialize our data representation of JSON to Decodable struct and pass it down to the next operator.
We also use eraseToAnyPublisher operator here. It is a helper operator for Type Erasure. Since the Publisher protocol has two associated types, it can be used only as a generic constraint, and we can’t return it from the function. The Combine framework provides AnyPublisher with a generic struct for boxing type erasured instance of Publisher, and this operator converts Publisher to AnyPublisher box type.
It’s time to move on to the usage of GithubService class. Let’s dive into the source code of ViewController which makes requests using GithubService.
In the fetchRepos function on top of GithubService, we use an operator called Catch. We use it to map errors into the empty values. Instead of dealing with errors, we convert them into an empty array of Repo structs. It allows us to assign the emitted value of this Publisher to any writable KeyPath of the same type as Publishers output, and as soon as a value is assigned the table reloads. The Assign method returns a cancellation token which we can use later to cancel our request. I really like how the Combine framework uses Swift language features like KeyPaths.
Today I’ve demonstrated the brand new FRP framework released by Apple. The best thing about Combine is the deep integration with the Swift Foundation. Combine provides ready to use Publishers for URLSession, NotificationCenter, etc. In the next posts, we will cover more Combine related topics like Subscribers and Subjects. Thanks for reading and see you next week! 😊