In Bite #162, we took our first look at RxSwift, and how it can transform how we write code. We learned how Observables can simplify our code, and mentioned creating our own Observables briefly, but today we'll dive a bit deeper. Let's begin:
Creating our own Observables is how we can bring code that wasn't built with reactive principals in mind, into the RxSwift world. It's helpful to think of Observables as merely a slightly different way to organize code we were already writing.
Let's look at a simple asynchronous function call:
let task = loadSpaceships { spaceships, error in
guard error == nil else { handleError(error); return }
self.resultsTableView.reloadData()
}
We can actually use this code as a starting point to write a new function that wraps this code and converts it into an Observable.
We'll be responsible for sending values along, reporting any errors, and letting observers know if/when the work is completed.
func spaceships() -> Observable<[Spaceship]> {
return Observable.create { o in
let task = loadSpaceships { spaceships, error in
guard error == nil else { o.onError(error!); return }
o.onNext(spaceships)
o.onCompleted()
}
return AnonymousDisposable { task.cancel() }
}
}
We use Observable's create
function to get a reference to an observer in a closure. We can use this observer to send along relevant status updates.
Lastly, we return an AnonymousDisposable closure that cancels the NSURLSessionDataTask when we're disposed.
Now this code can live in the RxSwift world as an Observable, be subscribed to, and be used alongside any other Observables:
Observable.zip(crew(), spaceships()) { return ($0, $1) }
.subscribeNext { print($0) }
One last note: We've been talking about all of this in terms of RxSwift, but other reactive or functional libraries might have different names for their streams of values. Even if we're using something other than RxSwift, the underlying concepts will usually remain largely the same. We can still use the techniques here to lift the code out of the conventional world and into the reactive one, regardless of which library we're using.