iosswiftuikitcoordinator-pattern

How do I apply the coordinator pattern to the tabBar?


I want to apply the coordinator pattern to the tab bar.

First, my AppCoordinator

class AppCoordinator: Coordinator {
   let window: UIWindow?
   var navigationController: UINavigationController
   var childCoordinator: [Coordinator] = []
   var parentCoordinator: Coordinator?
    
    init(_ window: UIWindow?, navigationController: UINavigationController) {
        self.window = window
        self.navigationController = navigationController
        window?.makeKeyAndVisible()
    }
    
    func start() {
        var tabBarController = setTabBarController()
        self.window?.rootViewController = tabBarController
    }
    
    func setTabBarController() -> UITabBarController {
        let tabBar = UITabBarController()
        
        let firstItem = UITabBarItem(title: nil, image: Image.mainImg, tag: 0)
        let secondItem = UITabBarItem(title: nil, image: Image.searchImg, tag: 1)
        let thirdItem = UITabBarItem(title: nil, image: Image.likePostImg, tag: 2)
        let fourItem = UITabBarItem(title: nil, image: Image.profileImg, tag: 3)
        
        
        let firstCoordinator = MainCoordinator(navigationController: navigationController)
        firstCoordinator.parentCoordinator = self
        childCoordinator.append(firstCoordinator)
        let firstVC = firstCoordinator.startPush()
        firstVC.tabBarItem = firstItem
        
        let secondCoordinator = SearchCoordinator(navigationController: navigationController)
        secondCoordinator.parentCoordinator = self
        childCoordinator.append(secondCoordinator)
        let secondVC = secondCoordinator.startPush()
        secondVC.tabBarItem = secondItem
        
        let thirdCoordinator = LikePostCoordinator(navigationController: navigationController)
        thirdCoordinator.parentCoordinator = self
        childCoordinator.append(thirdCoordinator)
        let thirdVC = thirdCoordinator.startPush()
        thirdVC.tabBarItem = thirdItem
        
        tabBar.viewControllers = [firstVC, secondVC, thirdVC]
        
        return tabBar
    }
}

And my MainCoordinator:

class MainCoordinator: baseCoordinator {

    func startPush() -> UINavigationController {
        
        let MainVC = MainViewController(viewModel: .init(coordinator: self))
        
        navigationController.setViewControllers([MainVC], animated: true)
        return navigationController
    }
}

searchVC and likePostVC are the same.

However, my execution result was as follows:

enter image description here

Why is my execution result like this?


Solution

  • I think you need a coordinator for your tabBarController. And in start of that coordinator you add your child coordinators to your tabBarCoordinator.

    I always had login flow before tabBar, and on start of AppCoordinator I initialize login and set appCoordinator.rootViewController to loginCoordinator.rootViewController. This is how I use coordinators with tabBar:

    class AppCoordinator() {
          func start() { 
          // Mostly initializing login.
          // somehow loginCoordinator triggers coordinatorDelegate.goToTabBar()
       }
    
       func goToTabBar() {
        tabBarCoordinator = TabBarCoordinator(root: root, dependencies: dependencies)
        tabBarCoordinator.coordinatorDelegate = self
        tabBarCoordinator.start()
       }
    }
    

    And here is how I start my TabBarCoordinator:

    class TabBarCoordinator {
     func start() { 
         let tabBarController = TabBarController()
         
         let firstCoordinator = //
         children.append(firstCoordinator)]
         firstCoordinator.start()
         
         let controller1 = UIViewController()
         controller1 = firstCoordinator.rootViewController
    
        // Do the same for second..
        
       tabBarController.viewControllers = [controller1, controller2]
       rootViewController.show(tabBarController, sender: nil)
       }
    

    And here is how to initialize sub coordinators:

    class FirstCoordinator {
        func start() { 
         let firstVC = FirstViewController()
         let navController = UINavigationController(rootViewController: firstVC)
         rootViewController = navController
        }  
    }
    

    I tried to simplify the code, it might not the direct answer you are looking for but i think it will be helpful to understand the pattern. }