22.
Debugging with RxTimelane
Written by Marin Todorov
In this short chapter, you will learn the basics of debugging RxSwift code with Timelane. Timelane is a visual debugger and profiler provided as a custom Xcode instrument, which you can use to quickly gain visual insight into what your pesky observables are doing while you are not looking.
Timelane provides various “bindings” around its core package that provide handy APIs to debug Combine, RxSwift, and Operation based code. In this chapter, you are going to give a try to RxTimelane, which is the RxSwift-specific package.
Installing the Timelane Instrument
Before getting started, you’ll need to install Timelane, which you can get from https://github.com/icanzilb/Timelane.
Once installed in your Applications folder, open Timelane and install the Timelane Instrument by clicking on the package icon:
This will spawn a standard Instruments installation dialog; click “Install”:
This will install the Timelane Instrument alongside your standard instruments like Zombies, Time Profiler, Core Animation, etc:
Using the RxTimelane library
The second step you need to take before getting started with debugging is to include the RxTimelane package in your project.
In this chapter, you’ll work on the Combinestagram app that you built in Chapters 4 and 6. You will continue on the project where you left off at the end of Chapter 6, “Filtering Operators in Practice!”
For this chapter, you’ll notice an additional dependency in your Podfile:
pod 'RxTimelane', '1.0.9'
Open the starter folder for the current chapter and install the dependencies via CocoaPods. You will notice that the two additional pods are installed alongside RxSwift and RxCocoa:
Installing RxTimelane (1.0.9)
Installing TimelaneCore (1.0.10)
TimelaneCore is the package that all Timelane packages share, while RxTimelane is the one providing the RxSwift-specific APIs.
The lane(…) operator
Open the starter project for this chapter. In MainViewController.swift add a new import at the top of the file:
import RxTimelane
Debugging with RxTimelane is based on using a custom operator called lane(). Inside viewDidLoad(), insert a line below the first use of images (and directly above throttle) like so:
images
.lane("Photos")
.throttle(.milliseconds(500), scheduler: MainScheduler.instance)
lane logs any events being passed through the subscription at the precise point you insert the operator. In simpler words, lane will automatically log in Instruments any new subscriptions, any values the observable emits, and also any completion and error events.
In Xcode, click Product ▸ Profile or press Cmd-I to instrument the Combinestagram app and select Timelane to open the Timelane Instrument:
The main UI components in the Timelane window are:
- A lane where observable subscriptions are plotted.
- A lane where all emitted values are plotted.
- A drop-down menu offering aggregations (filters).
- A table displaying details for the selected lane.
- A search field to filter the details grid.
Click on the record button on the top-left of Instruments (the button with the red circle). That will start the instrumentation of Combinestagram in your Simulator. Use the app as usual and select a few photos to create a collage.
You will see the images observable visualized in Timelane like so:
You see that the “Photos” lane is subscribed immediately upon start — a green “Active” bar is plotted as long as the app runs.
Additionally, each time you add a new photo to the collage you see a little signpost. If you hover with the mouse above one (like in the image above) a little popup will show you what value was emitted.
In the case of “Photos” you see a list of UIImage objects which is not very easy to parse — instead, show just the number of photos in the array.
Back in MainViewController.swift replace lane("Photos") with:
.lane("Photos", transformValue: { "\($0.count) photos" })
This way, instead of just logging the object description in Timelane, you will see the description you return in transformValue.
Click Product ▸ Profile in Xcode’s menu and start a new profiling session. This time when you add a few photos to the collage you can inspect the emitted values a bit easier:
You just learned how to inspect your observables at runtime! You can see for how long an observable was active (aka “subscribed”) and which values it emitted.
Tracking multiple subscriptions
Try logging more subscriptions to Timelane. You can use lane as much as you like. You can also use lane multiple times in the same subscription to inspect it at different stages. Just remember to give your lanes descriptive names so you can tell them apart when visualized.
Scroll down to this line:
let newPhotos = photosViewController.selectedPhotos
And add a new lane just below, so it looks like this:
let newPhotos = photosViewController.selectedPhotos
.lane("New Photos")
.share()
The new lane will plot the subscriptions to your photo selection view controller’s observable.
Start a new profiling session and present the photo selection controller a few times while adding each time a few photos to the collage. Timelane will plot something along the lines of:
You see when a subscription to newPhotos starts and you see it completed when you navigate back to the main view controller. If you present the photo selection controller multiple times Timelane will visualize the repeating subscriptions to the same observable via multiple bars in the same lane.
Finally, note that once a subscription completes it turns a different color so you can quickly see which subscriptions are active (green color), completed (blue), failed (red), or canceled (orange).
Inspecting values over time
To wrap up this very quick introduction to Timelane, see how you can inspect in a little more detail the values emitted by one of your observables.
Open PhotosViewController.swift and verify if the photo library authorization observable emits the values depicted on the flowcharts in Chapter 6.
First, import RxTimelane at the top of the file:
import RxTimelane
In viewDidLoad, insert a lane operator in your code like so:
let authorized = PHPhotoLibrary.authorized
.lane("Photo Library Auth")
.share()
This will log all the states of the photo library authorization. To verify this works, go ahead and delete Combinestagram from your Simulator (click and hold on the app’s icon to get to the contextual menu).
Start a new profiling session and click on the plus button in Combinestagram, then approve the access to the device’s photos library. Inspect the data in Timelane:
You can see that the authorization lane was active for a while and it completed at some point (when you clicked Allow in the alert box). Hovering over the little signposts will give you the emitted values but try a different approach this time.
Select the “Events Over Time” lane and look at the details data grid at the bottom of the window — it gives you all values in a handy tabular view like so:
And in case you have multiple lanes going on and the data table is getting crowded, use the drop-down menu to filter to the subscription you’re most interested in.
Click Events Over Time ▸ All Events by Subscription to get a list of the tracked subscriptions — click on the arrow button to filter the data grid to display only the values for “Photo Library Auth”:
As a last resort in case you have many values logged in the table and so even limiting to a single subscription doesn’t help you find the values you need; you can use the filter field at the bottom of the window to further filter the table contents.
Where to go from here?
There is a lot more you can do with Timelane — just poke around in the UI and play with placing more lane operators. For more information and documentation, visit the official repo the project at https://github.com/icanzilb/Timelane.