Coordinator pattern with UINavigationControllers and a UITabBarController

Viewed 1403

I'm trying to learn how to integrate coordinator pattern into iOS development.

I have an app which like this. In the storyboard, it looks like this. The navigation controllers and tabbars are not added in the storyboard because according to coordinator pattern, they will be added programatically.

enter image description here

The first view controller is PhoneViewController which takes user's phone number. This view controller is embedded in a navigation controller. After entering the phone number, it moves to the VerifyPhoneViewController. After verification, it moves to MainViewController a tabbarcontroller which contains three tabs. Each of these view controller will have a separate navigation controller of their own.

I have a protocol which contains all the necessary properties and functions each coordinator needs to implement.

protocol Coordinator {
    var childCoordinators: [Coordinator] { get set }
    var navigationController: UINavigationController { get set }

    func start()
}

I created a separate coordinator called AuthCoordinator for the authentication flow part of the app.

class AuthCoordinator: Coordinator {
    var childCoordinators = [Coordinator]()

    var navigationController: UINavigationController

    init(navigationController: UINavigationController) {
        self.navigationController = navigationController
    }

    // The initial view
    func start() {
        let phoneViewController = PhoneViewController.instantiate()
        phoneViewController.coordinator = self
        navigationController.pushViewController(phoneViewController, animated: false)
    }

    func submit(phoneNo: String) {
        let verifyPhoneViewController = VerifyPhoneViewController.instantiate()
        verifyPhoneViewController.coordinator = self
        verifyPhoneViewController.phoneNo = phoneNo
        navigationController.pushViewController(verifyPhoneViewController, animated: true)
    }

    // Move to the tabbarcontroller
    func main() {
        let mainViewController = MainViewController.instantiate()
        navigationController.pushViewController(mainViewController, animated: true)
    }
}

The navigation works fine. However there's a small issue.

Notice after moving to the tabbarcontroller, the titles don't show in the navigationbar when I switch between view controllers (I do set them in viewDidLoad method of each view controller). Plus the back button to VerifyPhoneViewController is still there too.

enter image description here

The issue is obvious. The navigationcontroller I initialized for the AuthCoordinator is still there at the top. I'm literally pushing the MainViewController on to that stack.

func main() {
    let mainViewController = MainViewController.instantiate()
    navigationController.pushViewController(mainViewController, animated: true)
}

What I can't figure out is a way to not do it like this. I can hide the navigationbar in the start method but then it's not ideal because well, it hides the navigationbar and I don't want that.

func start() {
    let phoneViewController = PhoneViewController.instantiate()
    phoneViewController.coordinator = self
    navigationController.navigationBar.isHidden = true
    navigationController.pushViewController(phoneViewController, animated: false)
}

Is there a different way to keep the navigationcontroller for the duration of the auth flow and then discard it when/soon after showing the MainViewController?

The demo project is uploaded here.

0 Answers
Related