skip to Main Content

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?

2

Answers


  1. I see two issues:

    1. make parentConordinator weak to prevent retain cycles
    2. you are passing the same navigationController to all your tab roots. That cannot work and is probably the reason for the problem you are seeing.
    Login or Signup to reply.
  2. 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.
    }

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search