RxSwift: Transforming Operators in Practice
Learn how to work with transforming operators in RxSwift, in the context of a real app, in this tutorial taken from our latest book, RxSwift: Reactive Programming With Swift! By Marin Todorov.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
RxSwift: Transforming Operators in Practice
35 mins
- Getting Started With GitFeed
- Fetching Data From the Web
- Using map to Build a Request
- Using flatMap to Wait for a Web Response
- share vs. shareReplay
- Transforming the Response
- Processing the Response
- Intermission: Handling Erroneous Input
- Persisting Objects to Disk
- Add a Last-Modified Header to the Request
- Challenges
- Where to Go From Here?
In the previous tutorial on transforming operators, you learned about the real workhorses behind reactive programming with RxSwift: the map
and flatMap
dynamic duo.
Of course, those aren’t the only two operators you can use to transform observables, but a program can rarely do without using those two at least few times. The more experience you gain with these two, the better (and shorter) your code will be.
In that previous tutorial (which is also based on a chapter from our RxSwift book) you already got to play around with transforming operators in the safety of a Swift playground. Hopefully you’re ready to take on a real-life project! You’ll get a starter project, which includes as much non-Rx code as possible, and you will complete that project by working through a series of tasks. In the process, you will learn more about map
and flatMap
, and in which situations you should use them in your code.
Without further ado, it’s time to get this show started!
Getting Started With GitFeed
Download the starter project for this tutorial here. The project is up to date with Xcode 8.2.1 and RxSwift 3.2.
I wonder what the latest activity is on the RxSwift repository? In this tutorial, you’ll build a project to tell you this exact thing.
The project you are going to work on in this tutorial displays the activity of a GitHub repository, such as all the latest likes, forks, or comments. To get started with GitFeed, open the starter project for this tutorial, install the required CocoaPods, and open GitFeed.xcworkspace.
The app is a simple navigation controller project and features a single table view controller in which you will display the latest activity fetched from GitHub’s JSON API.
https://github.com/ReactiveX/RxSwift
, but if you’d like to change it to any other repository of your choice, feel free.
Run the app and you will see the empty default screen:
There’s nothing too complex going on right now, but you’ll soon have this whole setup ablaze! :]
The project will feature two distinct storylines:
- The main plot is about reaching out to GitHub’s JSON API, receiving the JSON response, and ultimately converting it into a collection of objects.
- The subplot is persisting the fetched objects to the disk and displaying them in the table before the “fresh” list of activity events is fetched from the server.
You will see that these two complement each other perfectly — and there are plenty of opportunities to use both map
and flatMap
to build what’s required.
Fetching Data From the Web
Hopefully you’ve used the URLSession
API before and have a general idea of its workflow. In summary: you create a URLRequest
containing a web URL and parameters, then send it off to the Internet. After a bit, you receive the server response. In this tutorial, to use URLSession
the Rx way, you will simply use a solution boxed with RxCocoa — RxSwift’s companion library.
If you peek into GitFeed’s Podfile, you will notice that you import two different CocoaPods: RxSwift
and RxCocoa
. What gives?
RxCocoa is a library based on RxSwift, which implements many helpful APIs to aid with developing against RxSwift on Apple’s platforms. In an effort to keep RxSwift itself as close as possible to the common Rx API shared between all implementations such as RxJS, RxJava, and RxPython, all “extra functionality” is separated into RxCocoa.
You will use the default RxCocoa URLSession
extension to quickly fetch JSON from GitHub’s API in this tutorial.
Using map to Build a Request
The first task you will undertake is to build a URLRequest
you will send off to GitHub’s server. You will follow a reactive approach that might not make sense immediately, but don’t worry — when you re-visit that part of the project later on, you will appreciate it!
Open ActivityController.swift and peek inside. You configure the view controller’s UI in viewDidLoad()
, and when you’re finished, you call refresh()
. refresh()
in turn calls fetchEvents(repo:)
and hands over to it the repo name "ReactiveX/RxSwift"
.
It is in fetchEvents(repo:)
where you will add most of your code in this section. To get started, add the following:
let response = Observable.from([repo])
To start building the web request, you begin with a simple string, which is the repository’s full name. The idea to start with a string instead of directly building a URLRequest
is to be flexible with the observable’s input.
Next, take the address string and create the fully qualified URL
of the activity API endpoint:
.map { urlString -> URL in
return URL(string: "https://api.github.com/repos/\(urlString)/events")!
}
You use a couple of shortcuts to create the full URL by using a hard-coded string and force unwrapping the result. You end up with the URL to access the latest events’ JSON.
Have you noticed that you specified the closure’s output type? Did you really have to do that? The obvious answer is no; usually you don’t need to explicitly spell out closure input and output types. You can usually leave it to the compiler to figure those out.
However, especially in code where you have several map
and/or flatMap
operators chained together, you might need to help the compiler out. It will sometimes get lost in figuring out the proper types, but you can aid it by at least spelling out the output types. If you see an error about mismatched or missing types, you can add more type information to your closures and it’ll probably fix the problem.
But enough about compiler woes — back to coding!
Now that you have a URL
, you can move on to transforming it into a complete request. Chain to the last operator:
.map { url -> URLRequest in
return URLRequest(url: url)
}
Easy enough: you use map
to transform a URL
to a URLRequest
by using the provided web address.
Nice work! You’ve chained a couple of map
operators to create a more complex transformation:
Now it’s time to bring flatMap
into play and fetch some JSON.