Navigation in iOS, you are doing it wrong.

Scott
2 min readSep 23, 2022

Refer to this Hacking with Swift article.

Maybe I should create a series called, “Ditch that design pattern for encapsulation.”

I love the publication Hacking with Swift. I have benefitted greatly from the content they produce. This article is more a criticism of the coordinator pattern and how it is implemented industry wide. Since Hacking with Swift is widely read, I am using its article as a reference.

Without further adue, let me introduce the Coordinator implementation they propose.

Foundations

New types introduced: 3+, lines ~96, call stack depth: 3, Choices 2+*, new functions: 6, new properties: 6

Here is what I propose instead:

New types introduced: 0, lines ~44 call stack depth 2: Choices 0, new functions: 2, new properties: 0

Both keep the navigation call to a one liner. While my version has a few more characters, its more explicit. You don’t have to hop around any files to eventually find that the navigation controller is used, and that pushViewController or to turn on or off the animation. While the stack depth is 2.

A point goes to encapsulation

Additive/subtractive Changes

Lets evaluate how both approaches handle additive changes. First the coordinator:

New types introduced: 0+, lines ~17, call stack depth: 3, Choices 2+*, new functions: 1, new properties: 1

If a developer feels fancy enough to add another Coordinator, then new types would increment. I’m wary of those that are fancy in code.

Another metric could be remembering to add stuff, like coordinator property and Storyboarded conformance. If the developer forgets to add the Storyboarded conformance, they might be frustrated as the code won’t compile, but if they forget to add the coordinator property, they will have runtime non crashing errors. Which is pretty bad.

Here is the alternative.

New types introduced: 0+, lines ~17, call stack depth: 3, Choices 2+*, new functions: 1, new properties: 1

I would say a point goes to encapsulation.

Editing Changes: p1 adding payload arguments.

Ideally we wouldn’t have changes at every call site for a reusable component, but both encapsulation and coordination require changes at the call site.

Coordination:

Encapsulation:

For the encapsulation I added an instantiation method for the payload.

If want changes to be reflected everywhere the flow is called, then you can group the functions accordingly in the encapsulation method.

When implemented that way, changes to one place reflect as well.

Summary

2 points to encapsulation, and 1 tie with a preference for encapsulation.

--

--