How to make friends with UIKit
Bohdan Orlov
5071

Nice write up, Bohdan!

I liked the ViewControllerLifecycleBehaviour concept; will try to hook it up into the application I’m currently working on.

However, I disagree on the usage of the viewControllerForPresentation and encourage you to not use that. Let me explain why.

From my personal experience, the more navigation logic is spread, the more inconsistent and unpredicted application state becomes.

With the time it becomes harder to work in the codebase with hidden dependencies. Having transient dependency is not always bad; it allows you to better understand the dependency graph.

When you open a class and you see an id<NavigationDelegate>, you know that this class or any other class down the hierarchy use that to request a required navigation action. When a new engineer opens a view controller or a router which implements that delegate (s)he can understand the flow with an ease.

One more disadvantage of this approach is that with the time it may lead to even more hidden dependencies.

Consider the following scenario:

You have a view inside a view inside some other view … inside view controller which has a button responsible for presenting something. You implement that via:

func buttonPressed() {
let featureViewController = FeatureViewController()
viewControllerForPresentation()?.present(viewController: featureViewController)
}

In the next version of the app, you decide to add a subscription and make this feature available only to subscribed users. It makes this presentation conditional.

Of course, you can refactor it and implement it differently. However, practice shows, that most of the time the code ends up being:

func buttonPressed() {
if (SubscriptionManager.shared.isSubscribed) {
let featureViewController = FeatureViewController()
viewControllerForPresentation()?.present(viewController: featureViewController)
} else {
let subscriptionViewController = SubscriptionViewController()
viewControllerForPresentation()?.present(viewController: subscriptionViewController)
}
}

Our view suddenly became smart.

If you would implement it via the injected id<NavigationDelegate>, your code inside the view would remain untouched between both version:

func buttonPressed() {
navigationDelegate?.requestPresentation(of: .feature)
}

The only place where the code would change is the view controller implementing that delegate.

Looking forward to reading your new posts ;) It’s been a while.

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.