
Decouples routing between ViewControllers
// From navigationController?.pushViewController(AboutViewController(), animated: true) // to navigate(.about)- Decouples Viewcontrollers
- Testable navigation
- Faster compile times
A cool side effect of extracting navigation logic on big projects is improving compilation times. Indeed Strong dependencies due to navigation code often makes Xcode recompile files you never modified. Router enables you to extract your routing logic in a separate file.
enum MyNavigation: Navigation { case about }struct MyAppNavigation: AppNavigation { func viewcontrollerForNavigation(navigation: Navigation) -> UIViewController { if let navigation = navigation as? MyNavigation { switch navigation { case .about: return AboutViewController() } } return UIViewController() } func navigate(_ navigation: Navigation, from: UIViewController, to: UIViewController) { if let myNavigation = navigation as? MyNavigation { switch myNavigation { case .about: from.navigationController?.pushViewController(to, animated: true) } } } }In AppDelegate.swift, before everything :
Router.default.setupAppNavigation(appNavigation: MyAppNavigation())You can now call nagivations from you view controllers :
navigate(MyNavigation.about)Bridge Navigation with your own enum type, here MyNavigation so that we don't have to type our own.
extension UIViewController { func navigate(_ navigation: MyNavigation) { navigate(navigation as Navigation) } }You can now write :
navigate(.about)Another cool thing about decoupling navigation is that you can now extract traking code from view Controllers as well. You can be notified by the router whenever a navigation happened.
Router.default.didNavigate { navigation in // Plug Analytics for instance GoogleAnalitcs.trackPage(navigation) }There is a nasty bug in Swift 3 compiler where the compiler rebuilds files even though they haven't changed. This is documented here : https://forums.developer.apple.com/thread/62737?tstart=0
Due to this bug, the compilation can go like this :
Change ViewController1 -> Build
-> Compiles ViewController1, referenced in MyAppNavigation so
MyAppNavigation gets recompiled. MyAppNavigation is referenced in AppDelegate which gets recompiled which references ... App -> ViewController2 -> ViewController3 -> ViewControllerX you get the point. Before you know it the entire App gets rebuilt :/
A good this is that most of the app coupling usually comes from navigation. which Router decouples.
We can stop this nonsense until this gets fixed in a future release of Xcode. Router can help us manage this issue by injecting our AppNavigation implementation at runtime.
In your AppDelegate.swift
// Inject your AppNavigation at runtime to avoid recompilation of AppDelegate :) Router.default.setupAppNavigation(appNavigation: appNavigationFromString("YourAppName.MyAppNavigation"))And make sure your AppNavigation implementation is now a class that is RuntimeInjectable
class MyAppNavigation: RuntimeInjectable, AppNavigation {github "freshOS/Router" Simply Copy and Paste Router.swift files in your Xcode Project :)
Grab this repository and build the Framework target on the example project. Then Link against this framework.
