While working on several projects with SwiftUI and The Composable Architecture I approached some problems designing navigation flow. Let's assume the following scenario:
- We have an app with a feature, that can be used only if a user provides some details in advance.
- This feature has a separate screen in the app.
- Before a user can access this screen, we want her/him to provide some details using another screens (if she/he didn't do it before).
For simplicity, we can assume the following conditions:
- The app should work on iPhone only.
- Navigation happens on a stack of screens (in
UIKitapp I would basically use
UINavigationControllerto implement the coordination between the screens).
- There is no need to support other cases of the UI (no need to use
To be more concrete about the screens flow in the app, I prepared some example:
- When the app is launched,
Mainscreen is presented
- On the main screen user can tap on a button, that navigates to the
- However, if the user didn't provide some details (for example a phone number, set security PIN etc), before we go to the
Featurescreen, we need to present set of other screens that allow providing those details.
- There should be always a navigation back button visible, so the user can resign from providing the details and go back to the
Mainscreen of the app
Normally, when working with
UIKit I would implement the above requirements using
UINavigationController, with the help of some coordinator that decides which screen should be presented next and calls
setViewControllers([UIViewController], animated: Bool) function on the navigation controller whenever navigation should happen.
I am struggling with implementing such flow in a SwiftUI app and The Composable Architecture. I don't think the
NavigationLink provided by SwiftUI are a good fit for my needs, so I decided to wrap a
UIViewControllerRepresentable . I created a navigation state, which holds an array of screen-related states, in a similar way that navigation controller holds an array of view controllers. It works, but I am not sure how to correctly design store-scoping and reducers pullbacks. As a workaround, I am creating a separate store for each of the screens, and explicitly updating the navigation state from each of the screen-reducers.
Looking forward to exchanging experience and thoughts with talented developers that are reading this forum
You can find proof-of-concept implementation of the above on my GitHub: https://github.com/darrarski/TCACoordinatorDemo
Feel free to give feedback, even if you don't have a concrete solution for my problem. I will appreciate all hints and ideas!