#1 iOS — Reinventing view controller navigation
Forget about segues.
Few things about segues:
- Apple’s out of the box navigation solution defined in storyboard file
- hard to inspect if you have many view controllers on one storyboard
- not good enough in more complex cases
I just don’t like them. Naming is weird. API-s are weird. I also don’t like storyboards. When reviewing other developers’ code it is just impossible to see what is going on in the xml, not to mention the pain in resolving git conflicts.
CoreNavigation is 100% code based and does not yet support segues. However, you can still use view controller instances initiated from storyboards.
It’s time to boost some coding skills.
View controller navigation
Many modern app architectures wrap navigation logic but developers for some reason like to couple app’s business logic with
UIKit navigation APIs. Things get messy when a client makes the request for a new feature, e.g. deep linking or state restoration. More edge cases arise when users can have multiple access levels in the app and client wants some ACL mechanism implemented to warn the user, or to intercept, redirect or even disable navigation. I know this sounds like custom business logic but it can be abstracted. Abstracting common use cases requires some deeper knowledge of
UIKit navigation behavior and
CoreNavigation wraps these things for you.
The most common thing we do while navigating between screens is passing data to destination view controller. Developers tend to create custom initialisers with destination data as method arguments. This is OK for small apps (2–3 screens). Bigger apps — big no-no.
Perceive this problem as building your own town.
Small app — small town. Each of its districts is your view controller. They are connected with roads — these could be your segues. People, bikes, and cars traveling between districts are the data passed to view controllers. If the town is small enough there will be no need for road signs, people will know the path so custom initialisers on view controllers are fine. This could all be defined in a single storyboard file.
More view controllers — more need for greater control
As your town gets bigger, you’ll need to provide some traffic lights to people. Roads become highways — no more segues. Traffic lights are your custom navigation logic, e.g. green light can be letting authenticated user navigating to wanted destination view controller (district).
Letting other apps open certain view controller via deep linking is just letting tourists visit your town. Your town would need an airport or road connection with an outside world. Read more about universal linking.
Sometimes you may find yourself working in multiple-teams environment (huge apps like facebook, uber, etc.) where each team is building their own towns and you are not allowed to make any roads on your own. There is another team connecting the towns with each other and outside world.
For years I have to deal with the case where view controllers have several ways of navigating:
Truncated data (e.g. userId string) is passed to destination view controller which is opened immediately. Destination view controller animates a spinner while fetching full data. Fetching completion triggers layout on view controller’s view.
Full data (e.g.
Userobject) is passed to destination view controller which is opened immediately. There is no loading animation as data is already present.
Truncated data with preloading (least used)
Truncated data (e.g.
userIdstring) is used to preload full data (e.g.
Userobject) which is passed to destination view controller. During the data fetching loading animation is displayed on origin view controller.
Things get interesting when one view controller needs to be able to consume both data types, truncated and full. In the first case, origin view controller would have full data and in the other case would have just a reference to a full data. Questions arise:
- Should data be fetched before navigation or after?
- How to design a data model for destination view controller?
- Where to put the code for navigation?
- Where to put the code for fetching data?
- When using state restoration, should data be reloaded or restored from cache?
- How to extract and map deep link data parameters?
Whatever the answers are, the conclusion is we need some wrapper around view controllers. They cannot stand for themselves in a world of deep links, conditional navigation, state restoration, caching etc. They need support.
In the following post I am going to talk about new term —