Practical Combine: An introduction to Combine with real examples
Learn Combine from the ground up with a solid theoretical foundation and real-world examples of where and how Combine can help you move from writing imperative code to writing reactive code that is flexible, clean and modern.
The book has a total of 14 chapters and comes with a Playground and sample projects that show the code from the chapters in a way that allows you to experiment with the code directly, and expand your knowledge about Combine even quicker.
Chapter overview
Chapter 1 - Introducing Functional Reactive Programming
Learn the basic building blocks of Combine and Functional Reactive Programming (FRP). I explain what FRP is, and how it can help you write better and cleaner code. You'll immediately see little bits and pieces of Combine code to help you see how FRP enhances code readability in certain cases. You'll also learn about some of the very superficial differences between RxSwift and Combine. This will help you understand where Combine fits in the FRP ecosystem, and it will help you choose between the two frameworks if your app is for iOS 13 and above.
Chapter 2 - Exploring publishers and subscribers
Publishers are the bread and butter of the Combine framework. Without publishers, we'd have nothing to subscribe to. In this chapter you will learn how publishers work, how you can subscribe to the values they publish, and more importantly, you'll learn what all of this means. After going through a basic example, you will learn about the lifecycle of a subscription stream, and how subscribing to a publisher works exactly.
Chapter 3 - Transforming publishers
In most cases, the values that are published by a publisher need to be modified before they can be used by a subscriber. In this chapter, I demonstrate the usage of several of Combine's built-in operators like map, flatMap, and compactMap. We'll also cover some more advanced operators like replaceNil and setFailureType. You will also learn about operators that might throw an error to end the publisher stream, like tryMap for instance. We'll wrap up the chapter by defining a custom operator on Publisher that bundles a couple of other operators in a convenient wrapper.
Chapter 4 - Updating the User Interface
In this fourth chapter, we're finally going to get truly practical. You will learn how you can use Combine to update the value of a label with a new subscriber called assign(to:on:). You will also learn how Combine can be used in an MVVM-like architecture, and how it can be used to drive a collection view's diffable data source without implementing any specific architecture. On top of updating a collection view data source, I also demonstrate how you can use Combine to download images that need to be displayed in a collection view cell. And to top it all of, you'll learn how to build a Combine-driven theme manager that can be used to allow a user to switch your app between dark- and light mode separate from the system setting.
Chapter 5 - Using Combine to respond to user input
In this chapter, you'll learn how to implement several simple bindings between UI components and a model. Once you understand how this works in UIKit, I'll demonstrate how the same principle is implemented in SwiftUI because a lot of this functionality comes for free in SwiftUI. You'll also learn how you can restrict the processing of user input through a feature called debouncing. This is especially useful if you're building a feature where user input results in expensive processing like networking for example. You will also learn about the different mechanisms that Combine offers to merge and combine the output from multiple publishers into a single publisher. By the end of this chapter, you should have a very good understanding of how publishers in Combine can be updated, and how they can be used to integrate a model and user interface element with Combine.
Chapter 6 - Using Combine for networking
Throughout the preceding chapters, I often use networking as an example of a Combine publisher. The usage of networking examples so far has been very basic though. In this chapter, you will gain a more advanced understanding of networking in Combine, and how Combine can help you support features like low data mode on iOS, or how you can implement graceful error handling. In addition to networking, you will learn about some interesting new operators like tryCatch and switchToLatest. You'll implement a pretty complicated token refresh flow with these new operators, and a couple of operators you're familiar with at this point. This chapter doesn't stop there. I will also show you how you can orchestrate several network calls at once, and merge their outputs into a single publisher. By the end of this chapter, you will have all the knowledge needed to implement a robust networking layer with Combine.
Chapter 7 - Wrapping existing asynchronous processes with Futures in Combine
Not all of your asynchronous code is easy to integrate with Combine. In this chapter, you will learn about a very special publisher called a Future. This publisher doesn't quite play by the same inferred rules as other publishers, but it's a very convenient publisher that allows us to kick off asynchronous work, and broadcast the result of this work to its subscribers. You will learn how to implement a simple Future based interface on top of UNUserNotificationCenter, and I will show you how to wrap your own asynchronous code in a Future.
Chapter 8 - Understanding Combine's Schedulers
In Combine, a lot of threading and dispatch queue related logic is hidden from you, and that's extremely convenient. However, there are times where you might need to do some manual work to make sure a certain publisher sends its events on the main queue, or you might want to make sure that it doesn't run code on the main queue. Combine abstracts dispatch queues behind schedulers. Learn how schedulers work in this chapter, and find out how they impact the code you write in your apps.
Chapter 9 - Building custom publishers and subscribers
This chapter comes with a huge warning. Nothing in this chapter should be used in production. However, we will conceptually pull apart what happens when you subscribe to a publisher using sink by reimplementing the functionality. Apple does not recommend that users of Combine do this, and it's for good reason. The fine details of how subscriptions work are hidden from us as users of the framework. Regardless, I personally like to re-implement functionality in an attempt to better understand how it might work which can lead to interesting insights.
Chapter 10 - Debugging your Combine code
Debugging is hard, especially when you're dealing with asynchronous code. In this chapter, you will learn more about Combine's `print` operator and you will learn about a community tool called Timelane that can be used to visualize the lifecycle and emitted values of your Combine subscriptions.
Chapter 11 - Testing code that uses Combine
In this chapter, you will learn how you can use XCTest to write unit tests for your Combine code. You will learn things that you should, and shouldn't do when testing Combine code. I will also show you how you can optimize your code for testability and I will show you two convenient helpers that can help you improve and clean up your test suite.
Chapter 12 - Driving publishers and flows with subjects
Learn how you can build really powerful and complex features using Combine's PassthroughSubject, CurrentValueSubject, and some clever operators. You will learn how to deal with a paginated API in Combine, how you can recursively load data and I will show you an alternative approach to retrying network calls after a token refresh.
Chapter 13 - Combine in an async world
With Swift Concurrency and Swift 6.0 being available it's pretty clear that the use cases for Combine have changed. That said, Combine still has its uses. Even when you're targeting iOS 18 or newer, Combine fills various gaps that are not, or not properly covered in Swift Concurrency. This chapter outline the gaps that currently exist in Swift Concurrency, and how Combine is still relevant to solve these specific use cases.
Chapter 14 - Where to go from here
While this book should prepare you for a lot of Combine use-cases, there's also a lot that I don't cover. In this chapter, I aim to give you some insights into the features I didn't cover, and resources you might want to pick up to further deepen your Combine knowledge and expertise.
You'll get the book in epub and PDF format and a zip file with a Playground and sample projects.