By Casey Liss
 

When iOS 6 added Do Not Disturb, I was overjoyed. This prevents my phone from buzzing or otherwise disturbing me during my usual sleeping hours; in my case, from ten in the evening until seven in the morning.

In the typical Apple fashion, they thought about this enough to allow your Favorite contacts’ phone calls to pass through DND and ring immediately. (See SettingsDo Not DisturbAllow Calls From) So, if Erin calls me, regardless of hour, my iPhone will ring, Do Not Disturb be damned. Unfortunately, however, this did not apply for text messages; even messages coming from Favorites were silenced.

Thanks to this post from Katie Floyd, I’ve learned in iOS 10, that doesn’t have to be the case. You can engage “Emergency Bypass” for an individual contact and allow their calls and text messages to ring through, regardless of Do Not Disturb settings. To do so, go to their contact card, and go to set their Ringtone or Text Tone. In there, you’ll find a toggle for Emergency Bypass.

Unfortunately, however, Emergency Bypass doesn’t honor your phone’s vibration settings. My expectation was that when I have my phone silenced using the side switch, Emergency Bypass will allow my phone to vibrate, but it would not make any audible tone. Instead, it allows my phone to actually make the text tone, not respecting the side switch. Bummer.

Nevetheless, should you have someone in your life that you want to make sure can get a hold of you, your own social setting be damned, this is hidden gem.


Christmas Card Mail Merge

Since Erin and I are adults with a child, we sent out holiday cards this year. Rather than hand-addressing them like Erin has done in prior years, I wanted to create and print address labels. Since the source of all this data is stored in the Contacts app on my computer, I figured this would be easy.

It can be, but it wasn’t for me.

The Easy Way

If you’re willing to make precisely zero edits to the address labels that are created from the Contacts app, it’s actually quite easy to print labels.

  1. Select all the addresses you want to print by ⌘-Clicking on the ones you want
  2. FilePrint
  3. Select Contacts in the centered drop down, and then set the type of labels you have. In our case, we had bought Avery 8160.
  4. Print
Print dialog

The Hard Way

For me, I wanted to address couples as, say, “Stephen and Merri Hackett”, even if my contact card had only Stephen’s name in it. This got very complex very quickly, but I was able to figure it out.

  1. Select all the addresses you want to print by ⌘-Clicking on the ones you want
  2. Open Numbers (presumably this would work in Excel too) and create a new blank document
  3. Drag the addresses from Contacts into Numbers
  4. Remove any fields you don’t care about. This is, most likely, nearly all of them, such as phone numbers, emails, etc.
  5. Make any edits to the data here in Numbers. This is where, for example, I changed:
    Stephen HackettStephen & Merri Hackett
  6. FileExport toCSV to export the list as a series of comma separated values
  7. Go to Avery’s web site and select the YouPrint option
  8. Enter your product number (in our case, 8160)
  9. Select a Design
  10. On the left hand side, choose Import Data
  11. Upload your CSV you created in step #6
  12. Walk through each address and make sure that none run off the edge of the label
  13. Print

Quite obviously, this was considerably more involved. However, it also had the side benefit of me being able to use a slightly more festive label thanks to Avery’s selection of clip art designs.


RxSwift Primer: Part 5

Together, in my RxSwift primer series, we’ve:

Today, we’re going to tackle something we probably should have been doing all along: unit testing.

A Quick Digression on Unit Testing

Unit testing is, for some reason, a bit controversial. To me, I wouldn’t ship code without decent unit test coverage any sooner than I’d drive without a seatbelt on. While neither can guarantee your safety, both are reasonably low cost ways to improve your chances.

Many iOS developers I know—particularly indies—don’t seem to have the time for unit testing. I’m not in their shoes, so I can’t really argue. That being said, if you have any spare time in your day, I can’t speak highly enough about how helpful I’ve found unit testing to be.

TDD is 🍌 though. No one does that, right?

Architecture Changes

We left things here, with our ViewController looking like this:

class ViewController: UIViewController {

    // MARK: Outlets
    @IBOutlet weak var label: UILabel!
    @IBOutlet weak var button: UIButton!
    
    // MARK: ivars
    private let disposeBag = DisposeBag()
    
    override func viewDidLoad() {
        self.button.rx.tap
            .scan(0) { (priorValue, _) in
                return priorValue + 1
            }
            .asDriver(onErrorJustReturn: 0)
            .map { currentCount in
                return "You have tapped that button \(currentCount) times."
            }
            .drive(self.label.rx.text)
            .addDisposableTo(disposeBag)
    }

}

As written, this code works great. Truth be told, there’s a good argument to be made that it isn’t even worth unit testing. However, as with everything in this series, this is just barely enough to allow us to see how we could unit test it.

The first thing we need to do is separate the pieces in that Observable chain. As written, there’s no easy way to test what’s going on in the ViewController.

A whole discussion could be had about architecture here. I may approach that at a later time. For now, suffice it to say, we’re going to introduce two new types.

Event Provider

The EventProvider is a struct that carries any Observables that are being emitted from ViewController. These Observables are anything that drive business logic. In our case, our business logic is the counter, and the Observable that drives that is the button tap. Thus, here is our entire EventProvider:

struct EventProvider {
    let buttonTapped: Observable<Void>
}

Presenter

Taking a cue from VIPER, the Presenter is where business logic happens. For us, that’s as simple as incrementing the count, or really, the scan. Here’s the entire Presenter:

struct Presenter {
    
    let count: Observable<Int>
    
    init(eventProvider: EventProvider) {
        self.count =
            eventProvider.buttonTapped.scan(0) { (previousValue, _) in
                return previousValue + 1
            }
    }
    
}

The general path of communication is as such:

Architecture Diagram

The ViewController exposes its Observables to the Presenter by way of the EventProvider. The ViewController enrolls in Observables that are Properties on the Presenter itself.

Aside: Alternatively, you could choose to have the Presenter emit a ViewModel that encapsulates the entire state of the view. For simplicity, I’m just emitting the count by way of an Observable<Int> exposed on the Presenter.

Here is our revised ViewController that takes advantage of the new Presenter by using an EventProvider:

class ViewController: UIViewController {

    // MARK: Outlets
    @IBOutlet weak var label: UILabel!
    @IBOutlet weak var button: UIButton!
    
    // MARK: ivars
    private let disposeBag = DisposeBag()
    private lazy var presenter: Presenter = {
        let eventProvider = EventProvider(buttonTapped: self.button.rx.tap.asObservable())
        return Presenter(eventProvider: eventProvider)
    }()
    
    override func viewDidLoad() {
        self.presenter.count
            .asDriver(onErrorJustReturn: 0)
            .map { currentCount in
                return "You have tapped that button \(currentCount) times."
            }
            .drive(self.label.rx.text)
            .addDisposableTo(disposeBag)
    }

}

The real differences are the addition of lazy var presenter and the implementation in viewDidLoad(). We’re storing the presenter as a property so it never falls out of scope until our entire ViewController does. We’re using a lazy property so that we don’t have to make it optional, but can still create it after init time.

The chain in viewDidLoad() is mostly the same as we had seen before, except that we are using the presenter's count property to drive everything. A way to diagram this out is:

ViewController.button.rx.tap drives
EventProvider.buttonTapped, which drives
Presenter.count, which drives
our map and Driver, which drives
ViewController.label.rx.text

Everything is wired up as we expect, if slightly less linearly. Since I’ve been using an architecture similar to this at work for months, this reads very clearly to me now. If you’re scratching your head, that’s not unreasonable at this stage in the game. Nonetheless, by using an architecture like this, we now have separated our concerns:

  • The view controller is simply in charge of maintaining the user interface
  • The presenter is in charge of business logic
  • The event provider is what will need to be faked

Now we know what we need to unit test: the Presenter.

Unit Testing Observables

Remember what I said about Observables way back in part 2:

At the end of the day, just remember that an Observable is simply a representation of a stream of events over time.

It’s the end that makes things a little bit dodgy:

stream of events over time

How do we represent that in a unit test, that’s supposed to run and return immediately? Clearly, we need a way to fake signals on input Observables (like our EventProvider) and a way to capture the results on output Observables (like our Presenter).

Preparing for Unit Testing

Thankfully, RxSwift has a peer that we can take as a dependency only for the purposes of testing: the appropriately named RxTest.

Let’s amend our Podfile; I’m showing only the relevant portion:

  # Pods for RxSwiftDemo
  pod 'RxSwift'
  pod 'RxCocoa'

  target 'RxSwiftDemoTests' do
    inherit! :search_paths
    # Pods for testing
    pod 'RxTest', '~> 3.0'
  end

Once we do a pod install, we have some new features available to us. Most notably, TestScheduler.

Creating our Unit Test

A TestScheduler allows you to fake one or more Observables by defining at what time they should signal, and what those signals should be. The unit of measure for “time” is largely irrelevant; the tests will run as fast as the host machine allows.

In order to unit test our Presenter, we will create a fake Observable that we will feed into our EventProvider. This will, in turn, get fed into our Presenter. Since we know exactly how this fake Observable will signal, we can know exactly how the resulting count from the Presenter should signal.

We’ll create a new unit test class, and we’re going to store two instance variables within it: a DisposeBag and this new TestScheduler. We will also reset them between each test in the class, to ensure each test starts from a clean slate. So our test class looks like this, with imports included for reference:

import XCTest
@testable import RxSwiftDemo
import RxSwift
import RxTest

class RxSwiftDemoTests: XCTestCase {
    
    var disposeBag = DisposeBag()
    var scheduler: TestScheduler!
    
    override func setUp() {
        super.setUp()
        self.scheduler = TestScheduler(initialClock: 0)
        self.disposeBag = DisposeBag()
    }
}

Now we need to leverage the scheduler. Let’s create a test case.

In the test case, we will have to follow these steps:

  • Create a hard-coded list of events to drive the faked buttonTapped stream
  • Create an Observer to observe the results of the count stream
  • Wire up our EventProvider and Presenter
  • Wire up the Observer
  • Run the scheduler
  • Compare the results to what we expect

Let’s take a look at each step:

Create a Fake Stream & Observer

To create the fake stream, we’ll use our TestScheduler's ability to create an Observable. We have to choose between a hot and cold observable, which is a whole other topic[1], but just rest assured that hot will generally be a fine choice, especially for UI-sourced streams. We’ll fake it by specifying what events happen at what times:

let buttonTaps = self.scheduler.createHotObservable([
    next(100, ()),
    next(200, ()),
    next(300, ())
])

This can be approximated using this marble diagram:

---[@100]---[@200]---[@300]--->

Basically, at time 100, time 200, and time 300, we’re simulating a button tap. You can tell because we’re doing a next event (as opposed to error or complete) at each of those times.

Now we need something to observe the result stream. We don’t need the actual stream we’re observing yet; we simply need to know what type it is:

let results = scheduler.createObserver(Int.self)

Later, we’ll use that results observer to interrogate what values were signaled on the Presenter's count: Observable<Int>.

Wiring Everything Up

This portion is standard unit testing: pass your fakes into your objects under test. For us, that means passing our buttonTaps observable into a new EventProvider, and then passing that into a Presenter:

let eventProvider = EventProvider(buttonTapped: buttonTaps.asObservable())
let presenter = Presenter(eventProvider: eventProvider)

Running the Scheduler

Now we need to actually run the scheduler, which will cause the buttonTap stream to start emitting events. To do so we need to do two things. First, we ensure that we’re capturing what’s emitted by the Presenter in our Observer:

self.scheduler.scheduleAt(0) {
    presenter.count.subscribe(results).addDisposableTo(self.disposeBag)
}

Note that we’re scheduling this enrollment at time 0. Given the way we’ve set up buttonTaps, we can do this any time before time 100. If we do it after time 100, we’ll miss the first event.

Now, we actually tell the scheduler to run:

scheduler.start()

Testing the Results

By this point, the scheduler will have run, but we still haven’t tested the results. We can do so by comparing what’s in our Observer to a known expected state. Note that the expected state happens at the same times as our faked buttonTaps, but the values are the results of the scan operator:

let expected = [
    next(100, 1),
    next(200, 2),
    next(300, 3)
]

Now, thanks to an overload provided by RxTest, we’ll do a normal XCAssertEqual to confirm the results match what we expected:

XCTAssertEqual(results.events, expected)

Let’s look at the whole thing all together:

func testPresenterCount() {
    let buttonTaps = self.scheduler.createHotObservable([
        next(100, ()),
        next(200, ()),
        next(300, ())
    ])
    
    let results = scheduler.createObserver(Int.self)
    
    let eventProvider = EventProvider(buttonTapped: buttonTaps.asObservable())
    let presenter = Presenter(eventProvider: eventProvider)
    
    self.scheduler.scheduleAt(0) {
        presenter.count.subscribe(results).addDisposableTo(self.disposeBag)
    }
    scheduler.start()
    
    let expected = [
        next(100, 1),
        next(200, 2),
        next(300, 3)
    ]
    
    XCTAssertEqual(results.events, expected)
}

A quick ⌘U to run the test, and we see what we hoped for:

✅

You can see the final version of this code here.

Now, feel free to modify buttonTaps, expected, or the time we used in scheduleAt() to see how tests fail. Also pay attention to the Console output, as it does a good job of showing the difference between expected and actual.

Wrapping Up

My RxSwift Primer is, for now, complete. We’ve learned:

You now have all the tools you need to start writing your own code using RxSwift. For more help with Rx, I recommend:

Rx has made my code better in almost every measure. I’m really glad to have been introduced to it, and I can’t really imagine writing code any other way. Even though it’s a steep learning curve, and it requires rewiring your brain to think about problems differently, the juice is well worth the squeeze.

Good luck!

Acknowledgements

My thanks to Daniel “Jelly” Farrelly for pushing me to write this series, and for doing first-pass edits. You can hear Jelly and I discuss RxSwift on his now-complete podcast, Mobile Couch, on episode #93.

My thanks to Jamie Pinkham for introducing me to RxSwift, and for doing the technical edits on each of these posts.


  1. Observables can be either hot or cold. Cold Observables do not emit events until they are subscribed to. This is the default behavior for most Observables. Hot Observables will emit even if there are no subscribers. UI elements are examples of hot Observables: just because no one is listening for a button tap doesn’t mean it didn’t happen. You can find more details in the RxSwift documentation.


RxSwift Primer: Part 4

In my RxSwift primer series, we’ve:

Today, we’ll take this to the next step by leveraging a feature in RxCocoa.

Recap

When we left things, our ViewController looked like this:

class ViewController: UIViewController {

    // MARK: Outlets
    @IBOutlet weak var label: UILabel!
    @IBOutlet weak var button: UIButton!
    
    // MARK: ivars
    private let disposeBag = DisposeBag()
    
    override func viewDidLoad() {
        self.button.rx.tap
            .debug("button tap")
            .scan(0) { (priorValue, _) in
                return priorValue + 1
            }
            .debug("after scan")
            .map { currentCount in
                return "You have tapped that button \(currentCount) times."
            }
            .debug("after map")
            .subscribe(onNext: { [unowned self] newText in
                self.label.text = newText
            })
            .addDisposableTo(disposeBag)
    }

}

We’ve gotten rid of our stored state, leveraged the scan function, and used map to make it clearer what each step of the process does. Today, we’re going to introduce the Driver object.

Driver

If you wanted to push the result of an observable chain onto a UI element, such as the String we’re generating above, that’s fraught with peril:

  • What happens if that Observable errors? How does the UI element handle that?
  • What happens if the Observable is being processed on a background thread? Updating user interface elements from a background thread is a big no-no.

Enter the Driver.

A Driver is one of the “units” that is offered in RxCocoa. A Driver, like all the other units, is a special kind of Observable. In the case of a Driver, it has the following qualities:

  • It never errors
  • It is always observed on the main thread
  • It shares side effects

Of those, we’re going to focus on the first two.[1] It fixes both of our problems above:

  • What happens if a Driver errors? It can’t.
  • What happens if a Driver is being processed on a background thread? A Driver guarantees it will always be processed on the main thread.

Naturally, a Driver solves our problems. Furthermore, a Driver can drive the value of a UI element. This special trick of a Driver allows us to wire a UIControl to an Observable's output without any manual call to subscribe().

Using a Driver

To use a driver, we’re going to modify our ViewController code a bit. We’ll remove the subscribe() call entirely, and use the Driver to drive() the UILabel’s text property instead.

First, we have to create a Driver. The general way to do this is to simply convert an Observable to a Driver using the Observable's asDriver() function. Notice the parameter we have to provide to asDriver(), if we do the conversion right after the scan():

asDriver(onErrorJustReturn: Int)

Immediately, we hit something unexpected: we have to provide an Int in order to create the Driver. The reason why is clear from the parameter name: onErrorJustReturn. To convert an Observable to a Driver, we need to provide a value to use in case the source Observable errors. In our case, we’ll just use zero.

Here’s our new chain so far, before the call to subscribe():

self.button.rx.tap
    .debug("button tap")
    .scan(0) { (priorValue, _) in
        return priorValue + 1
    }
    .debug("after scan")
    .asDriver(onErrorJustReturn: 0)
    .map { currentCount in
        return "You have tapped that button \(currentCount) times."
    }
    .debug("after map")

A couple things should be noted here:

  • We can sprinkle calls to debug() before and after the conversion to Driver
  • We can use map on a Driver and it will remain a Driver

It’s important to really let that second bullet sink in: most Rx operators such as map, filter, etc. all work on Drivers. Conveniently, they also return Drivers. Given that, it doesn’t usually matter where the conversion to a Driver happens in a chain. I could have done it before the scan above, if I preferred. Just remember everything that comes after will be on the main thread.

Regardless of where I place the asDriver(), the result of the above chain is Driver<String>. Let’s leverage that to drive our UILabel's text property. We can do so using the Driver's drive() function:

self.button.rx.tap
    .debug("button tap")
    .scan(0) { (priorValue, _) in
        return priorValue + 1
    }
    .debug("after scan")
    .asDriver(onErrorJustReturn: 0)
    .map { currentCount in
        return "You have tapped that button \(currentCount) times."
    }
    .debug("after map")
    .drive(self.label.rx.text)
    .addDisposableTo(disposeBag)

We’ve now removed our call to subscribe(), and are simply asking the Driver to push updates onto the UILabel's rx.text property. We still need to add this to a DisposeBag, since there’s an implicit subscription made by the Driver. You don’t have to remember that, as there will be a warning if you forget.

Like before, let’s run, tap the button once, and see what is left in the console. Here again, I’ll add newlines for clarity:

2016-12-17 15:27:55.934: after map -> subscribed
2016-12-17 15:27:55.935: after scan -> subscribed
2016-12-17 15:27:55.936: button tap -> subscribed

2016-12-17 15:27:58.303: button tap -> Event next(())
2016-12-17 15:27:58.304: after scan -> Event next(1)
2016-12-17 15:27:58.304: after map -> Event next(You have tapped that button 1 times.)

This actually looks just the same as it did before. The fact that we’re using a Driver is irrelevant for the purposes of debug() as Drivers are really just a special kind of Observable.

Cleanup

Now that we know everything is working as intended, let’s get rid of our calls to debug(). Here’s the final, Rx-ified version of ViewController:

class ViewController: UIViewController {

    // MARK: Outlets
    @IBOutlet weak var label: UILabel!
    @IBOutlet weak var button: UIButton!
    
    // MARK: ivars
    private let disposeBag = DisposeBag()
    
    override func viewDidLoad() {
        self.button.rx.tap
            .scan(0) { (priorValue, _) in
                return priorValue + 1
            }
            .asDriver(onErrorJustReturn: 0)
            .map { currentCount in
                return "You have tapped that button \(currentCount) times."
            }
            .drive(self.label.rx.text)
            .addDisposableTo(disposeBag)
    }

}

🎉

You can see this version of the code at Github. Look at how pretty it is! I’m being silly, but also somewhat serious. This new code has several advantages over what we started with:

  • No stored state; all state is simply computed
  • Less chance for bugs because there is no stored state to get out of whack with the user interface
  • Dramatically improved local reasoning; it’s clear the steps we’re taking;
    • Start with the UIButton tap
    • scan all occurrences; start with 0 and add 1 each time
    • Convert that to a Driver to ensure we never error out and are on the main thread
    • Convert the Int to a String
    • Push that value into the UILabel
  • Furthermore, there’s no other methods involved, and no magical Interface Builder wiring

There is one disadvantage, however. This code is quite a bit longer than where we started:

class ViewController: UIViewController {

    // MARK: Outlets
    @IBOutlet weak var label: UILabel!
    
    // MARK: ivars
    private var count = 0
    
    @IBAction private func onButtonTap(sender: UIControl) {
        self.count += 1
        self.label.text = "You have tapped that button \(count) times."
    }
}

That’s unfortunate, but this is a really crummy example in that regard. I chose this example because I didn’t want to get bogged down in irrelevant details, such as UITableViews, etc. This example of simply counting how many times a button is tapped is way simpler than most uses of Rx.

The Canonical Example

Everyone’s favorite example of what makes Rx so great is handling a user entering a search phrase. In fact, I was part of a conversation with Brent Simmons and Jamie Pinkham about this back in April. There’s more discussion over at Brent’s site, where Brent contrasts a traditional way of writing this search handler with RxSwift. The ground rules were:

  • Changes to the search text must be coalesced over a period of 0.3 seconds.
  • When the search text changes, and the text has four or more characters, an http call is made, and the previous http call (if there is one) must be canceled.
  • When the http call returns, the table is updated.
  • And: there’s also a Refresh button that triggers an http call right away.

While there is a fair bit of supporting code that we had to write to make this happen in RxSwift, satisfying the above requirements was really easy. The meat of that effort is here:

let o: Observable<String> = textField.rx.text
    .throttle(0.3)
    .distinctUntilChanged()
    .filter { query in return query.characters.count > 3 }

You can see in that one line of code:

  • We’re triggering off a UITextField's text property
  • We’re throttling it so that we ignore changes that occur in less than 0.3 seconds
  • We’re ignoring two successive duplicates
  • We’re ignoring entries less than 3 characters

Boom. 💥 That is why RxSwift is so cool.

Next Time

There’s still more to be done, however. We’ve been bad developers, and haven’t been unit testing our code as we go along. In part 5 of the series, I’ll describe how to do unit tests in RxSwift. Much like RxSwift itself, unit testing it is both very unlike what we’re used to while also being extremely powerful.

UPDATED 29 December 2016 1:30 PM: Added clarifying remarks about the placement of asDriver() in an Observable chain.


  1. “Shares side effects” is Rx-speak for “every subscriber shares one common subscription”, in contrast with the usual behavior, where every subscriber gets its own subscription. That means that there will only ever be one subscribe or disposed event, even if there are multiple subscribers. If this is confusing, well, that’s why it’s a footnote. You asked. More on this in the docs.


RxSwift Primer: Part 3

So far we’ve:

Today, we’re going to start really leveraging Rx for what it’s best at: eliminating stored state, and thus, preventing avenues for bugs.

Recap

When we left things, our ViewController looked like this:

class ViewController: UIViewController {

    // MARK: Outlets
    @IBOutlet weak var label: UILabel!
    @IBOutlet weak var button: UIButton!
    
    // MARK: ivars
    private let disposeBag = DisposeBag()
    private var count = 0
    
    override func viewDidLoad() {
        self.button.rx.tap
            .debug("button tap")
            .subscribe(onNext: { [unowned self] _ in
                self.onButtonTap()
            }).addDisposableTo(disposeBag)
    }
    
    @IBAction private func onButtonTap() {
        self.count += 1
        self.label.text = "You have tapped that button \(count) times."
    }
}

This is fine, but it’s already obvious that something is redundant.

Quick Win

As a first step, let’s get rid of the useless onButtonTap(). We can just fold that into the subscribe():

class ViewController: UIViewController {

    // MARK: Outlets
    @IBOutlet weak var label: UILabel!
    @IBOutlet weak var button: UIButton!
    
    // MARK: ivars
    private let disposeBag = DisposeBag()
    private var count = 0
    
    override func viewDidLoad() {
        self.button.rx.tap
            .debug("button tap")
            .subscribe(onNext: { [unowned self] _ in
                self.count += 1
                self.label.text = "You tapped that button \(self.count) times."
            }).addDisposableTo(disposeBag)
    }
}

This is definitely an improvement, but there’s still many more things that we can do in order to make things better.

Scan

In the first part of this series, I said:

Rx brings a bunch of tools to the table; some are the ones we already know. Some are totally new. Once you get to know the tools, it’s easy to reason about what is being done to a stream.

Today we’re going to add a new tool to our toolbox: scan. The scan function is summarized on the official Rx site as:

Apply a function to each item emitted by an Observable, sequentially, and emit each successive value.

What?

In the documentation, there’s an interesting tidbit that sounds vaguely familiar:

This sort of operator is sometimes called an “accumulator” in other contexts.

This is still confusing though. Let’s see if we can make sense of this by checking out the marble diagram:

Scan marble diagram

Now this “accumulator” seems to make sense. With each new input (1, 2, 3, 4, 5), we seem to be adding that value to the sum of all previous values.

  • 1 + 0 = 1
  • 2 + 1 = 3
  • 3 + 3 = 6
  • 4 + 6 = 10
  • 5 + 10 = 15

Suddenly accumulator makes more sense. In fact, this looks very similar to vanilla Swift’s reduce() function.

Using Scan

So, how do we actually use scan? Looking at the way it’s declared gives us a hint:

public func scan<A>(_ seed: A, accumulator: @escaping (A, Self.E) throws -> A) -> RxSwift.Observable<A>

It looks like we provide a seed value, and then a closure to perform whatever accumulation we’d like. What if we seed the scan with 0? Rather than overwriting what we have, let’s do this separately:

let o = self.button.rx.tap
    .scan(0) { (priorValue, _) in
        return priorValue + 1
    }

Now, using Xcode’s quick info popover (⌥-Click), we can see what type o is:

RxSwift scan type info

Awesome! We’ve now got an Observable<Int>, which theoretically means we have an Observable that will signal the current tap count every time the button is tapped. Perfect!

Aside: I find it’s often useful to break one Observable chain up as we’ve done above, and leverage Swift’s type inference to ensure that I’m operating on the types I expect. In this contrived example, it’s pretty obvious what’s happening, but in more complex cases—especially when we begin combining streams—things get hairy quickly.

Additionally, the Swift compiler’s type inference often gets tripped up once you get to combining many different streams and mutating them. One easy way to cheat and get back into the compiler’s good graces is to split up these calls, and if necessary, annotate the types as required.

Wiring Up

Let’s dump our temporary variable o and use this scan. Further, let’s also add a couple debug()s for good measure. Our new chain now looks like this:

self.button.rx.tap
    .debug("button tap")
    .scan(0) { (priorValue, _) in
        return priorValue + 1
    }
    .debug("after scan")
    .subscribe(onNext: { [unowned self] currentCount in
        self.label.text = "You have tapped that button \(currentCount) times."
    })
    .addDisposableTo(disposeBag)

Notice something important here: we have two calls to debug():

  • Our existing one that hangs off of button.rx.tap
  • A new one that hangs off of the scan()

Let’s run the app, tap three times, then look at both the screen and output. I’d drop an animated GIF of the screen behavior, but it looks the same as it always did, which is a victory. Looking at the console output, I’ve added some newlines for clarity, but otherwise haven’t changed anything:

2016-12-16 21:55:12.661: after scan -> subscribed
2016-12-16 21:55:12.662: button tap -> subscribed

2016-12-16 21:55:15.807: button tap -> Event next(())
2016-12-16 21:55:15.807: after scan -> Event next(1)

2016-12-16 21:55:16.728: button tap -> Event next(())
2016-12-16 21:55:16.728: after scan -> Event next(2)

2016-12-16 21:55:17.628: button tap -> Event next(())
2016-12-16 21:55:17.628: after scan -> Event next(3)

Notice that not only are there two entries per event on the button.rx.tap Observable, one for each debug() call, but they are showing different "payloads". The first is the ()/Void we discussed last time. The second is the Int that comes out of scan. Pretty neat.

It’s important to remember that debug() shows you the state of the stream at that point in the composition. Sprinkling debug() calls throughout one composition, as we have done above, can tell you loads of information about your transformations.

Dropping State

Did you notice what else is different about the above? Before our scan, the subscribe() closure looked like this:

self.count += 1
self.label.text = "You tapped that button \(self.count) times."

After scan:

self.label.text = "You have tapped that button \(currentCount) times."

We’ve dropped our dependency on the count instance variable. In turn, this means we have no stored state in this class anymore. We can now safely remove count from the class entirely.

Now, Rx is starting to spread its wings: we have removed stored state, and as such, we’ve removed a potential avenue for bugs. Awesome! 🎉

You can see this version of the code at this commit.

Small Improvement

Though not strictly necessary, let’s demonstrate how we can split things out slightly. Sometimes it helps to split a compound operation into multiple individual operations for code clarity. Remember: clever code is hard to maintain code.

In our case, let’s leverage map to split out the generation of the message that is being sent to the UILabel:

self.button.rx.tap
    .debug("button tap")
    .scan(0) { (priorValue, _) in
        return priorValue + 1
    }
    .debug("after scan")
    .map { currentCount in
        return "You have tapped that button \(currentCount) times."
    }
    .debug("after map")
    .subscribe(onNext: { [unowned self] newText in
        self.label.text = newText
    })
    .addDisposableTo(disposeBag)

In this more verbose version of our Observable chain, it’s abundantly clear what is happening:

  • We’re reacting to events on a UIButton's tap stream
  • We’re scanning it to reduce it to a single Int
  • We’re mapping that Int and creating a String from it
  • We’re subscribe()ing to that Observable<String> and setting that String on a UILabel.

Yes, it’s quite a bit longer than the procedural version we started with. That’s a bummer, but in a contrived example like this one, it’s to be expected. Most systems using Rx are not this simple, and have far more wild things going on. Thus, in more complex examples of Observable streams, the savings are often considerable.

Regardless of how long it is, I’d argue this is actually an extremely approachable block of code. As I said above, it’s eminently clear what is happening. It’s clear what the input is, and how we’re mutating it to get to our final subscribe(). It’s so much easier to reason how this code works, since there’s no reliance on other functions, and no reliance on Interface Builder wiring.

Since we examined the console output from the scan, let’s take a look at how it looks with our newly introduced map. This time, I’ll only tap the button once, and I will continue to add newlines for clarity:

2016-12-16 22:13:41.517: after map -> subscribed
2016-12-16 22:13:41.518: after scan -> subscribed
2016-12-16 22:13:41.519: button tap -> subscribed

2016-12-16 22:13:45.766: button tap -> Event next(())
2016-12-16 22:13:45.766: after scan -> Event next(1)
2016-12-16 22:13:45.768: after map -> Event next(Optional("You have tapped that button 1 times."))

As exepected, through the various debug() calls, we can trace our button tap from ()1You have tapped the button 1 times. Very neat.

You can see this version of the demo app at this commit on Github.

Next Steps

We’ve now had a big win and removed all stored state in our ViewController. Next time, we’ll take things a little bit further, and leverage one of the higher order classes that RxCocoa makes available to us: the Driver. We’ll also clean things up a bit, and then take stock of where we’ve landed.


RxSwift Primer: Part 2

In order to learn about RxSwift, I wanted to come up with a completely contrived demo application that is written entirely in vanilla UIKit. We can then, step by step, convert that application to use RxSwift. The first couple of steps will be a bit hamfisted, but this will allow new concepts to be introduced slowly.

In part 1 of this series, we saw a visual representation of what this app does:

Demo app animation

This app is written using a storyboard (generally I prefer XIBs, but that’s a discussion for another day), and has a single UIViewController. The entirety of that view controller is below:

import UIKit

class ViewController: UIViewController {

    // MARK: Outlets
    @IBOutlet weak var label: UILabel!
    
    // MARK: ivars
    private var count = 0
    
    @IBAction private func onButtonTap(sender: UIControl) {
        self.count += 1
        self.label.text = "You have tapped that button \(count) times."
    }
}

As you can see, there’s not much to it. There is a UILabel to show how many times a button has been tapped. That button isn’t stored in the class, because it’s wired up to an IBAction. There’s no need to store it.

Unfortunately, we have to manually keep track of how many times the button has been tapped. This data is stored in count.

The @IBAction func onButtonTap(sender:) is the aforementioned IBAction, which is wired up in Interface Builder, and is called by UIKit when the button is tapped.

Naturally, this is all super easy code, and there’s not much to it.

You can see all of this code on GitHub. Note that this is one commit in that repository; if you want to cheat and read ahead, you can look at the commits that follow. Once this series is over, you can walk forward and backward through time by checking out each individual commit.

Converting to Rx

The first step to converting this to use Rx is to think of what the inputs and outputs are. What causes things to happen? What causes us to do a computation, or change what we present to the user?

In such a simple app, it’s quickly obvious that the UIButton being tapped is what kicks off a computation, and a change in state. As the button is tapped, we will need to continue to change the value of count.

Marble Diagrams

How would this transition of state look? Let’s model it over time:

---[tap]---[tap]---[tap]--->

equates to

---[ 1 ]---[ 2 ]---[ 3 ]--->

The above is a crude representation of a marble diagram. A marble diagram is a way of representing signals in the Rx world. The bar represents time. Above, quite obviously, we start on the left and work toward the right. Each tap on the upper diagram yields a different value on the bottom diagram.

Marble diagrams are great ways to show how operators work in Rx. A great example is map: the input is at the top, the output is at the bottom, and the map operation is in the middle:

Map marble diagram

In the example, the map is simply multiplying the input by 10, so 1 becomes 10, 2 becomes 20, and 3 becomes 30.

Aside: You’ll notice in some marble diagrams the arrows aren’t arrows at all, but actually lines. They’ll end with either | or X. A pipe represents a stream that has completed. These streams have declared that they will never signal again. An X represents an error. Streams that error do not continue to signal events after the error.

Coming back to our streams:

---[tap]---[tap]---[tap]--->

equates to

---[ 1 ]---[ 2 ]---[ 3 ]--->

Clearly, the place we start is with the UIButton being tapped. In order to get access to that button programmatically, we’ll need to add it to our view controller. I’ve done so, and called it button:

@IBOutlet weak var button: UIButton!

RxCocoa

RxSwift is a foundation; it works for any sort of Swift and is not specific to user interfaces, network calls, nor anything else. RxCocoa is, in short, UIKit wrapped in Rx. For work done on user interfaces, you’ll need to:

import RxSwift
import RxCocoa

Most UIKit controls will have reactive extensions, and in general, they’ll be exposed to developers in the rx property.

So, to get to the stream that represents taps of the button in our view controller, we need to use button.rx.tap.

Observables

button.rx.tap is a variable that returns a ControlEvent. A ControlEvent is a special kind of something else: an Observable.

Every time that I’ve said “stream”, what I’m really saying is “Observable”.

Observables are the way streams are represented in Rx. You can perform many operations on observables; that’s what the entire RxMarbles site is for.

Most things that you work with in Rx are related to, or can be converted to, an Observable. In fact, most higher-order types like ControlEvent can be converted to Observables by using .asObservable().

At the end of the day, just remember that an Observable is simply a representation of a stream of events over time.

Subscriptions

Generally speaking, the last operation you’ll perform on an Observable—on a stream—is to take action based on that stream signaling. In our case, how do we take action every time the button is tapped?

We will subscribe to that Observable. This allows us to provide a closure where we run whatever code we need. So, our code now looks like this:

self.button.rx.tap
    .subscribe(onNext: { _ in
    })

So what do we do inside this closure, when the Observable signals?

Wiring Up

For this first step, we’ll simply use the existing method we wrote for the procedural version of the app: @IBAction func onButtonTap(sender:). This is not the right way to do things in the Rx world, but let’s take things slowly, one step at a time. Thus, our new chain looks like this:

self.button.rx.tap
    .subscribe(onNext: { _ in
        self.onButtonTap(sender: self.button)
    }

Since we don’t need onButtonTap(sender:) to be an @IBAction anymore, we can get rid of the sender parameter. That cleans things up nicely:

self.button.rx.tap
    .subscribe(onNext: { _ in
        self.onButtonTap()
    }

Disposables

In principle, we can build and run right now, and things should work. However, if we do, we’ll see a build warning:

Result of call is unused.

Uh, what‽

In RxSwift, it’s important to clean up after yourself, and terminate Observables, especially network requests. Without getting too deep into the weeds, there is basically only one rule: when you see the above warning, add that object to a DisposeBag.

In our case, we’ll add a DisposeBag to our ViewController. This is because the lifetime of this subscription is tied to the lifetime of our view controller:

private let disposeBag = DisposeBag()

And then we’ll use it in our subscribe() call:

self.button.rx.tap
    .subscribe(onNext: { _ in
        self.onButtonTap()
    }
    .addDisposableTo(self.disposeBag)

Don’t let this put you off. There’s really nothing to managing resources, and having a way to reliably dispose of all active Observables comes in very handy from time to time. After a year of doing RxSwift, I’ve never had to think about disposal, outside of dropping things in a dispose bag.

Generally speaking, each class/struct that is doing subscribe()ing gets one shared DisposeBag, and all subscriptions get added to it. That’s it.

Debugging

With the code we have above, it will run, and it will work. However, what if we want to debug what’s happening within an Observable chain? Naturally, we can place a breakpoint within a closure–such as the one we’re providng to subscribe(). Sometimes, though, you want to see flow, even in places where we don’t have a closure to interrupt.

Luckily, RxSwift provides an easy way to handle this: debug(). Let’s change our chain to include a call to debug():

self.button.rx.tap
    .debug("button tap")
    .subscribe(onNext: { [unowned self] _ in
        self.onButtonTap()
    }).addDisposableTo(disposeBag)

And now let’s run the app, and click 3 times. Here’s the console output:

2016-12-15 19:02:31.396: button tap -> subscribed
2016-12-15 19:02:34.045: button tap -> Event next(())
2016-12-15 19:02:34.584: button tap -> Event next(())
2016-12-15 19:02:35.161: button tap -> Event next(())

The call to debug() will tell us when the Observable is subscribed to, as well as each time it has an event. As discussed above, Observables can signal:

  • Next (with a value)
  • Error (with an error; represented by a X in a marble diagram)
  • Completed (represented by a | in a marble diagram)

All of these will be shown by debug().

Though it’s a bit hard to tell above, debug() also shows us what value was signaled. In our case, the button tap is not just a ControlEvent, but in actuality a ControlEvent<Void>. That’s because a button’s tap doesn’t have any other data to it; all we know is, a tap happened. This is in contrast, say, to the value of a UISegmentedControl, where its value stream is a ControlEvent<Int>. The Int is the index of the selected segment. What good would it be to signal that the selected segment changed without the new selection?

Coming back to our button tap, the ControlEvent<Void>, which is a special kind of Observable, doesn’t really carry a value at all; its value is Void. In Swift, we can represent Void as (). That’s why you’re seeing Event next(()); this could alternatively be written as Event next(Void).

By contrast, if we were signaling with the current count—perhaps after a map—the above would read:

2016-12-15 19:02:31.396: button tap -> subscribed
2016-12-15 19:02:34.045: button tap -> Event next(1)
2016-12-15 19:02:34.584: button tap -> Event next(2)
2016-12-15 19:02:35.161: button tap -> Event next(3)

At first, debug() may seem like it’s just cluttering up your console. However, as we’ll learn in future posts, it’s extremely powerful, and can give you important insight into how your data is flowing through your streams.

Next Steps

Now we’ve dipped our toe into wiring up a procedural interface with Rx. So far, we haven’t really reaped any benefits. We’re simply calling into our old code differently. Having started here, we’re now one step closer to having a proper, Rx implementation.

In the next post, we’ll start to explore a more Rx-y way of going about implementing our view controller. This will include the real coup de grâce: getting rid of var count.


RxSwift Primer: Part 1

When I got to my current job, my team was just starting to look into Reactive Programming as the basis for our clean-room rewrite of our main app. I had never really heard of this before, and I was immediately intrigued.

I set out to learn more about reactive programming, and never found one great guide to answer my questions. Over the next several posts, I’ll attempt to provide exactly that.

Today, we’ll begin with the basic questions. What is Reactive Programming? What does it bring to the table? Why should I care?

What is Rx?

I’d summarize reactive programming (Rx) as:

Modeling a system using a series of composable streams of data, and eliminating stored state wherever possible.

That may not be the most pure academic definition, but that’s how I think of it.

The key to Rx is to think of everything as a series of inputs and outputs; to think of as much as possible as being asynchronous. We can model most systems—most especially user interfaces and network requests—as chains of composable streams.

What Does Rx Bring?

  • Stateless programming
    Naturally every application has some state, but Rx tries very hard to eliminate state. Rather than storing state, Rx attempts wherever possible to simply react to a change from the outside world. These changes may be network callbacks or user actions such as tapping a button.

  • Fewer bugs
    By eliminating state, we’re eliminating avenues for bugs to crop up. Bugs are often caused by the stored state of the world not agreeing with the actual state of the world. Say, for example, a cloud-based app where the local copy of user data is not in sync with the server’s. Naturally, Rx can’t eliminate all of this, but it can get rid of much of it.

    Even something as simple as keeping a data model in sync with a UI control can sometimes be buggy. With Rx, there’s often nothing to store, and thus, nothing to keep in sync, which in turn means fewer bugs.

  • Better local reasoning
    Rx brings a bunch of tools to the table; some are the ones we already know. Some are totally new. Once you get to know the tools, it’s easy to reason about what is being done to a stream. For example:

    self.button.rx.tap
      .withLatestFrom(segmentedControl.rx.value)
      .map { selectedIndex in
          return "You've selected #\(selectedIndex)."
      }
      .subscribe { message in
          print(message)
      }
      .addDisposableTo(disposeBag)
    

    In the above, we’re taking a button, and upon it being tapped, start to do work. The first thing we do is read the current value of a UISegmentedControl. Once we have that value, we generate a message which we’re printing to the console.

    We’re composing two streams: the button tap and the segmented control’s value, and then mapping the result into a string. Finally, we use that string to do work.

    All of that is easily reasoned from just looking at the properties and methods called above: tap, withLatestFrom(), value, map, and subscribe. It’s all right there.

  • Improved flexibility and speed
    Since everything in your world is (or should be) exposed as a stream, it’s easy to extend what you’ve already written to add new features, or to react to new requirements. So many otherwise-challenging business requirements become quite simple when it’s just a matter of combining streams.

    Just the other day at work, we had a situation where our product owner wanted us to only enable a button when some search filters were selected. Since the filter values are just exposed as streams, it was as simple as a
    withLatestFrom(filters).map {} to make the button enable/disable as a reaction to the state of the filters. It took no time.

  • Cross-language Equivalency
    Most modern languages have a native implementation of Rx. In the case of my job, we’re using RxSwift for iOS and RxJava for Android. If your “native tongue” isn’t Swift, that’s okay. These same ideas and methods should be available in your platform of choice. Check out the ReactiveX site for details.

    The advantage for us is, if the Android team solves a tough problem, it’s likely that the iOS team can crib their solution, platform differences aside. That’s very powerful, as it leads to us all speaking a common language, even though our actual languages are very different.

Why Should I Care?

Having worked in RxSwift since February, I’ve come to really love it. It’s taken me a long time to un-learn all the ways I’ve traditionally thought about writing code. I’m still struggling, from time to time, to truly understand the right—reactive—way to approach a problem.

For all the reasons enumerated above, I can’t imagine writing code the traditional way anymore. It feels so heavy, and bloated, and just… old.

Rx is a completely different way of thinking, and I’ve yet to meet someone that took to it well. It took me a couple months to really get to the point where I could understand it well, and write it with a modicum of efficacy. Almost a year on, I absolutely love it.


Over the next several posts, I’ll be taking the world’s most boring and simple demo application and converting it from traditional, procedural code to use Rx. I’ll be going over the changes one very small step at a time.

The demo application is a single UIView that has a UIButton and a UILabel. As you tap the button, it tells you how many times you’ve done so in the label.

It’s boring and stupid, but by design: in moving from traditional code to the new hotness, I don’t want any other irrelevant stuff clouding the discussion.

Here’s a visual demo of the app:

Demo app animation

In part two, we’ll start by quickly examining the code, written using vanilla UIKit, and then taking the first step of the conversion to Rx.


 

Remember, way back when, a month ago, when I said this:

Top Gear The boys are back, and I’m so excited to see what comes next.

I, um, well, hm.

As I write this, The Grand Tour posted episode 4 just a few days ago. My summary of these episodes is, roughly:

1: 😂
2: 😱
3: 🙂
4: 😕

I was tentatively excited—thrilled even—after the first episode. Boy was I in for a shock in episode two:

Episode three was closer to the Top Gear I used to love, but still not quite there.

Episode four was, at best, watchable. Which led me to this very uncomfortable feeling:

I had my attention called to a spot-on article in The Guardian reviewing the season so far. It summarized, so well, some of my thoughts so far:

Worse, with the pool of cash Amazon provides, it’s cranked up these irksome indulgences to the point where bolts are popping out. The kernel of what made Top Gear a phenomenon – three men bickering, driving around and being rubbish – is almost entirely absent.

The author, Luke Holland, seems to have come to the same conclusion as I have:

One of the most acute mistakes Clarkson’s iteration of Top Gear increasingly made was its blurring of the line between presenter and actor. May, Hammond and Clarkson are good presenters; they were never good actors. And it was the show requiring them to act that resulted in its most tiresome segments.

And in a fitting summary:

It’s frustrating, because this is such an easy show to get right. Three men, talking about cars, mocking one another, and going on adventures. That’s it. Stop scripting everything, and stop throwing money at pointless explosions. It’s tiresome.

I take some issue with saying it’s “easy” to get right. I think the formula is easy, and has few ingredients. The three hosts, a general outline of a plot, and then stand back and get out of the way. The execution, however, is far more challenging.


Today, Erin said to me:

I used to look forward to the banter between the three of them. Now I dread it.

Nailed it.

By no means am I giving up on The Grand Tour. As many are quick to well, actually point out—as though I’m not acutely aware of it already—the first two seasons of Top Gear were, well, quite rough. Here’s hoping we’ll look at this season of The Grand Tour in the same way: ambitious, but rubbish.


 

Today I joined Shelly Brisbin, Dan Moren, and Jason Snell on this week’s Clockwise. Four topics, four hosts, a ton of fun, in thirty minutes.

This week, we discussed Amazon Go, tech trends we just can’t seem to get behind, home-tech paranoia, and giving back.

Always a blast, I hope that Clockwise is as fun to listen to as it is to record.


The Holy Trinity

1 year, 8 months, 17 days.

The time between the last normally scheduled Top Gear of the Clarkson era, and the premiere of The Grand Tour.

Now in the past, that time—that absence—seems so short. In the middle of it, it seemed endless.

I recognize how absurd it is to talk this way about a television show. Nonetheless, this is the TV show. The one I would schedule my life around. My favorite, bar none.

I eulogized Top Gear. I spent 75 minutes discussing it. Hell, I eulogized a fan site for the show. We threw parties to celebrate it. My license plate on my car is an homage to it.

The work of these men has meant a lot to me, for many years.


This past Friday, the first episode of The Grand Tour was released on Amazon Prime Video.

The same three hosts, but a new name, a new format, a new corporate overlord.

I’ve been looking forward to this for six months now. I was so amped to see this new creation that perfection was not possible.

Damn if they didn’t come close.


📣 📣 📣
Beyond here, there be spoilers.
If you haven't watched the episode, you should.
📣 📣 📣

Look. At. This. Opening.

So. Much. Happiness.

Look at how damn happy they are. Look at how happy Clarkson is.

No, seriously. Look at Clarkson again:

:-D

And May:

:-D

And Hammond:

:-D

They’re back.

The opening sequence nearly brought me to tears. Truly. It’s absurd, but it’s true.


The Grand Tour opens with Clarkson making a walk of shame out of the BBC headquarters in dreary London. The musical accompanyment begins as simply a piano, forlorn, lovely, understated. We follow Clarkson to Heathrow, boarding a flight to Los Angeles. He picks up his rental car, a blue bespoke Mustang, in a parking garage. Leaving LAX, on a bright and sun-shiny day, the vocals in the background accompaniment start:

I can see clearly now; the rain is gone. I can see all the obstacles in my way…

On the road is when we see the scene above. Clarkson is met by his co-hosts, in matching red, white, and blue Mustangs. Mustangs that, like the wild animals they’re named after, are running free.

Driving in the desert, at speed, amongst a flotilla of cars of all shapes and sizes, our three heroes arrive at what appears to be a music festival—Burning Van—in the middle of nowhere. Suddenly, the question begins to make sense.

As the once-mellow opening song reaches a crescendo, our hosts emerge from their cars amongst a horde of screaming fans. It is somewhat self-indulgent, only getting worse as eight screaming jets do a low-altitude fly by over the crowd. And yet, it’s so… them. I can’t help myself smiling even larger.

The first real words of the show aren’t uttered until our boys arrive on stage, and begin to introduce each other. The hosts introduce each other one by one, mostly “taking the mickey” out of each other in the process.

The opener was perfect.


I have some problems with the first episode. Aside from the opener being a bit over the top, I felt like the segments in the tent needed work. The hosts, to my eye, looked visibly nervous. Some of the jokes, such as the Air Force and celebrity guests, fell very flat, and went on far too long.

By and large, though, I thought this first episode of The Grand Tour was great. It focused largely on cars, which is something Top Gear got dinged for forgetting to do toward the end of its run.

The title of the episode (we’re doing episode titles now, apparently) is reference to the boys finally getting to test “the holy trinity” together. We have seen the 918, P1, and The Ferrari pit against each other. Finally. Having the BMW M2 as the introduction to the “Eboladrome” didn’t hurt this BMW owner’s feelings either.


Top Gear The boys are back, and I’m so excited to see what comes next.