Solution

1. At first it would possibly look like an obvious solution is adding an extension to ViewController:

and it works as needed — write once, then reuse. But it’ll become messy when many transitions come. Xcode autocompletion doesn’t work well I know, but sometimes it can show you a lot of unnecessary methods. Even if you don’t want to show a profile from this screen, it’ll be there. So, go further and try to improve this one.

2. Rather than writing an extension to ViewController and have tons of methods in one place, let’s implement every route in a separated Protocol and use the awesome feature of swift — protocol extension.

Now, this approach is more flexible — we can extend a view controller with needed routes only (avoid tons of methods), just add a route to the controller’s inheritance. 🎉

3. But of course there’re some improvements:

What if we want to have a modal transition to the profile controller from all places except one? (it’s a rare case, but anyway).

Or more importantly — If I change the presentation type, I should change the type of a dismiss transition as well (present / dismiss).

We don’t have a chance to configure it for now, so it’s time to implement a Transition abstraction with few implementations — ModalTransition and PushTransition:

I reduced a bit the implementation logic of the ModalTransition just for simplicity. A full version is available in Github.

and the similar reduced logic of the PushTransition:

You definitely have noticed the Animator object, so it’s a simple protocol for custom transitions:

As I said earlier about a massive view controller, let’s add an object that comprises the whole routing logic and is contained as a property in a view controller. We meet Router — a base class for all future routers. 🎉

Please, spend a bit time to understand this code. This class contains two methods for opening and closing, a reference to a view controller and an openTransition in order to know how to close this module.

Now using this new class let’s update our ProfileRoute:

You can see that the default transition is modal and in openProfile method we generate new module and open it (of course it’s better to use a builder or factory to generate a module). Also, pay attention to a transition variable, profileTransition is saved to this variable in order to have one instance.

The next step is updating the Friends module:

We’ve created the FriendsRouter and added the needed routes via typealias. Here’s where magic happens! We use protocol composition (&) to add more routes and protocol’s extension to use a default implementation for routing. 😎

The last step in this story is how easily and nicely a close transition can be achieved. If you recall ProfileRouter, there we’ve configured openTransition and now we can take advantage of it.

I created a Profile module with only one route — close and when a user clicks a close button, we use the same transition type to close this module.

If necessary to change a transition type, just change it in the protocol extension of ProfileRoute and this code will continue working without any changes! Awesome, isn’t it?