How Not to Go Crazy Writing iOS Asynchronous Code Using Various Frameworks

Combine, async / await, and more

Jakub Kiermasz
Better Programming

--

While working with modern mobile applications, we often operate with asynchronous code, which is quite tricky.

The Swift team members do their best to make our life easier; thus, since 2021, we can use new async/await-based concurrency. It wouldn’t be iOS programming if we didn’t have another, not-so-old tool.

So we have the Combine framework packed into our arsenal. Easy composition of asynchronous operations and data streams is essential for programmers, so the community came out with the RxSwift before we even heard about Combine and Swift Concurrency being planned.

As you can see, there are many frameworks we can use for the compositional concurrency approach. We often end up having all of them used in a project. It was no different in my case. Once upon, I run into sinking data from Combine’s Publisher and performing async action inside Swift’s Task.

Using Combine, we need to hold a strong reference to keep receiving the Publisher’s emissions. Tasks are pretty different. They run no matter if you hold a reference. So, we need to keep one, cancel a task when required, and then release it. Sounds familiar? I bet it does.

If you’ve used RxSwift, for sure, you remember DisposeBag. Combine uses a similar approach with the Set<AnyCancallable>. So why not create a sack that helps store tasks and cancellables?

Let’s start by creating the API that will allow us to add our async magic to such a sack:

Since we know, what the API looks like, let’s created SubscriptionContainer that we could use.

It’s easy, thanks to AnyCancellable behavior. According to documentation: An AnyCancellable instance automatically calls cancel() when deinitialized.

Usage would look like this:

Now, observing Publishers will act the same, and container deallocation will cancel the Tasks. Please, be aware that the compiler makes capturing a strong reference to self easy because it’s being added implicitly.

While using the above SubscriptionContainer consider capturing self weakly.

Naturally, extending it to store RxSwift subscriptions can be easily added.

--

--