Cancelling Asynchronous Tasks with RxSwift

Drkc
Propeller Blog
Published in
3 min readNov 22, 2016

--

ReactiveX

A lot of times we utilize external libraries that use completion closures. For example, if you’re using a library to handle asynchronous tasks like Reactive Cocoa or RxSwift, you might want to add a wrapper around those tasks to have a nice, consistent API. Besides having a consistent API, you can employ all the awesome features that libraries provide like cancelling tasks, retrying failed requests, etc.

Say you want to populate a cell with an image after doing some work on the image, like applying a filter. For simplicity, let’s assume we always want to apply this filter before presenting the image in the cell.

SDWebImage + Cells

For our example, we’ll use the ultra-popular SDWebImage but it applies to any other image caching library. A basic implementation using MVC would look like the following:

Populating the cell with the image

The process of setting the image looks something like this:

  1. Fetch an image from cache.
  2. Fetch an image from network if not in cache, then cache it.
  3. Process the image (add an image filter).
  4. Present the new image on a cell’s imageView.

SDWebImage already handles 1 & 2 for us. The problems of reusing cells and having asynchronous code can be tricky for new developers. Since you never know when the task will finish executing, you can’t prevent the image to be set if you ever need to. To illustrate this, let’s break it into steps:

  1. Cell 0 fetches image 0
  2. Cell 0 is reused
  3. Cell 0 fetches a new image 4
  4. image 4 fetch completes, image 4 is displayed in cell 0
  5. image 0 fetch completes, image 0 is displayed in cell 0

Cell 0 ends up displaying image 0 when it should display image 4!

RxSwift to the Rescue

RxSwift is a library for composing asynchronous and event-based programs by using observable sequences. It’s part of ReactiveX, a cross platform library, supporting Java, JavaScript, C++, C#, etc. which means you can use it for both frontend and backend.

First let’s add an extension on SDWebImageManager to use Observables instead of closures. This way we can reuse this functionality and work with other Observables everywhere in the application. Here’s a simplified version:

Converting a closure into an Observable

An Observable element is generic, which allows the compiler enforce type constraints in our code. Let’s implement this extension in the cell. We will need a PublishSubject, which can forward signals to observers.

That’s all you need to do to be able to discard the requests when dequeuing cells 🎉. At the time of writing the use of flatMapLatest is actually in the sample code of RxSwift’s readme.

We should probably apply the image filter on background even if the work is trivial, but it’s good enough for this example.

Conclusion

Using the reactive programming paradigm can be a powerful abstraction about how our data flows. I’ve personally enjoyed using RxSwift. The clear composition of asynchronous operations makes code simple, elegant, and powerful. Of course all of this can be replicated without using any kind of reactive library. Maybe using NSProgress (introduced in iOS 7) makes more sense for you. If so, here’s a cool post about using it.

--

--