Nowadays, reactive programming with RxSwift has become the new buzz word in Swift programming. For me, the best way to understand a programming construct and the motivation behind it is to learn about the problems it solves. Asynchronous nested callbacks All our applications need some form of asynchronous programming, which traditionally means adding heavily nested callbacks. Nested callbacks are easy to implement but difficult to understand, read, and debug. This complexity only grows when you need to synchronize multiple asynchronous tasks. More often than not, easy is interchangeably used with simple but in many programming constructs simple is NOT easy. In this case, asynchronous callbacks can add complexity to your software. Nested callbacks are easy to implement but difficult to understand, read, and debug. In the code snippet below, an async task is created to download image from url, which on success is set on UIImageView on the main thread. Figure 1 — Nested code is difficult to understand, read, and debug In the above code snippet, we download the image on a background thread, and then update the imageView content by animating its alpha on the main thread. In iOS, the main thread renders UI and handles events. Grand central dispatch GCD — high level abstraction of threads in Swift — enables us to execute blocks asynchronously on dispatch queues. Blocks are simple to implement, as the task becomes complicated we end up writing nested blocks. Javascript community resolved this problem by making promises and async functions part of ES6 Javascript standards. Similarly, the Swift community adopted Functional Reactive Programming , with use of libraries such as RxSwift. What is Reactive Programming? Reactive programming is a way of responding to asynchronous streams of data. Figure 2 — Propagation of change or events In simple words, streams of data emitted by one component are captured by another that subscribe for data changes. In Figure 2, streams of data emitted by the observables are processed by an operation, which in-turn emits the desired output along with a completion signal. Figure 3 — Propagation of error In Figure 3, the error thrown by the operation is emitted in the onError callback without triggering the completion signal. The concept of data streams is not something new; tap or click events are asynchronous event streams on which we can observe on and perform actions. In reactive programming, data streams are captured asynchronously by a defining callback functions that both execute when a value or error is emitted and a completion signal is posted. Data streams are first class citizens. Therefore, data manipulation is simplified with functions such as map, flat map, reduce, filter, concat, merge, etc. It registers to Observables that emit data streams with the help of subscribeOn method. The observer receives the streams of data in the onNext callback and errors are recorded in the onError callback. Finally, the onComplete callback is triggered; informing the subscriber all observables operations are done. This only happens after the entire data stream is emitted successfully. The observeOn operator specifies the thread on which the observer receives events, whereas subscribeOn specifies the thread on which work is executed. ObserveOn operator can be called multiple times per stream of data to move between threads but SubscribeOn can only be called once. By default units of work are scheduled on the CurrentThreadScheduler — schedules on current thread. Figure 4 — Refactored using RxSwift As events are single threaded, the onNext , OnError , and OnCompleted callbacks handle all the UI updates on the main thread in sequence. As our team became more familiar with RxSwift, we decided to refactor our networking layer by utilize reactive programming patterns. Figure 5 — Simplified Search location filter function A location fetch is triggered when assigning search fragments to MKLocationSearchCompleter. The results are returned within the completerDidUpdateWithResults observable delegate and then are filtered by flat mapping chaining in the filterSearchLocation operation. Figure 6 — Subscribe to MKLocationSearchCompleter query fragment search The flatMap operator will then transform the items emitted by completerDidUpdateWithResults observable and flatten the emissions into a single array of MKLocalSearchCompletion observable. The chained observables results are retrieved on subscription within the onNext and onError callbacks. The code snippet from Figure 6 is declarative. The behavior and logic is specified at the initialization of an observable, which prevents bugs in async event management. Each callback next, error on subscription is handled in sequence as events are single threaded. Along with pushing data streams to subscribers, observables can also return other observables. Chaining of observables is beneficial in writing readable code as the output of one asynchronous operation is fed into another operation. In our app, chaining observables are implemented in the network layer as we execute multiple sequential API requests. Strongly typed observables aid in self-documenting our code and reducing overall bugs. Figure 7 — Location Search Demo Conclusion Reactive programming sounds great so far, but it has some cons. RxSwift has a learning curve. It is not a golden hammer for all asynchronous problems, however we found it to be very beneficial in replacing KVO and state machine patterns. We have not adopted Rx in managing our UI with data binding as UIKit core delegate patterns are easy to use. Because of this, on-boarding new hires remains easy as engineers who are unfamiliar with RxSwift do not have to learn a new programming pattern or style. I would highly encourage teams to explore reactive programming. If you or your team have reservations using RxSwift in your project, introduce it selectively, like in the Network layer.