Router
  • September 14, 2023

⚠️ Deprecated and no longer supported. Use at your own risks.
This has been used extensively and after weighing up pros and cons, we now favour the use of native Flow Controllers or Coordinators as explained here.
The native route (pun intended) should always be favoured and we believe less dependencies is something we should always strive for.

Router


Why


Because classic App Navigation introduces tight coupling between ViewControllers. Complex Apps navigation can look like a gigantic spider web.

Besides the fact that Navigation responsibility is split among ViewControllers, modifying a ViewController can cascade recompiles and produce slow compile times.

How


By using a Navigation enum to navigate we decouple ViewControllers between them. Aka they don’t know each other anymore. So modifying VCA won’t trigger VCB to recompile anymore \o/

// navigationController?.pushViewController(AboutViewController(), animated: true)
navigate(.about)

Navigation code is now encapsulated in a AppNavigation object.

Benefits


  •  Decouples ViewControllers
  •  Makes navigation Testable
  •  Faster compile times

Get started


1 – Declare your Navigation enum

enum MyNavigation: Navigation {
case about
case profile(Person)
}

Swift enum can take params! Awesome for us because that’s how we will pass data between ViewControllers 🙂

2 – Declare your App Navigation

struct MyAppNavigation: AppNavigation {

func viewcontrollerForNavigation(navigation: Navigation) -> UIViewController {
if let navigation = navigation as? MyNavigation {
switch navigation {
case .about:
return AboutViewController()
case .profile(let p):
return ProfileViewController(person: p)
}
}
return UIViewController()
}

func navigate(_ navigation: Navigation, from: UIViewController, to: UIViewController) {
from.navigationController?.pushViewController(to, animated: true)
}
}

A cool thing is that the swift compiler will produce an error if a navigation case is not handled ! Which would’nt be the case with string URLs by the way 😉

3 – Register your navigation on App Launch

In AppDelegate.swift, before everything :

Router.default.setupAppNavigation(appNavigation: MyAppNavigation())

4 – Replace navigations in your View Controllers

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)

Bonus – Tracking

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)
}

Shave off compilation times


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 {

Installation


Carthage

github “freshOS/Router”

Manually

Simply Copy and Paste Router.swift files in your Xcode Project 🙂

As A Framework

Grab this repository and build the Framework target on the example project. Then Link against this framework.

GitHub


View Github

#freshos #microframework #navigation #router #routing #swift #viewcontroller
YOU MIGHT ALSO LIKE...
EEStackLayout

A vertical stackview which takes subviews with different widths and adds them to it's rows with paddings, spacings etc.

AudioManager

AudioManager is a Swift package that provides a modular and easy-to-use interface for implementing audio feedback in your applications. It ...

CameraBackground

Features Both front and back camera supported. Flash modes: auto, on, off. Countdown timer. Tap to focus. Pinch to zoom. Usage  

DKCamera

Description A light weight & simple & easy camera for iOS by Swift. It uses CoreMotion framework to detect device orientation, so ...