简体   繁体   中英

UINavigationControllerDelegate doesn't work when back twice

I use coordinator pattern with child coordinators. I have a problem with removing child coordinator of my child coordinator.

This is a sequence of my coordinators:

  1. HomeCoordinator -> RoutineCoordinator (child of HomeCoordinator) -> ExerciseCoordinator (child of RoutineCordinator) -> CustomExerciseCoordinator (child of ExerciseCoordinator)

To get know when user pops view controllers I use method didShow from navigation controller delegate.

When I push view controllers, everything is ok, but I when I move back, method didShow is called only once. When I use back button twice, the second time didShow is not called.

Example: I move back from CustomExerciseCoordinator to ExerciseCoordinator and didShow works properly. Then I immediately move back to previous coordinator (RoutineCoordinator) and didShow is not called.

I am not sure if it is needed to show all coordinators, because the code for each coordinator looks similar, but below it is shown.

  class HomeCoordinator: NSObject, Coordinator {
        
        var childCoordinators = [Coordinator]()
        var navigationController: UINavigationController
        
        init(navigationController: UINavigationController) {
            self.navigationController = navigationController
            
            navigationController.navigationBar.prefersLargeTitles = true
            navigationController.navigationBar.tintColor = .white
            super.init()
            navigationController.delegate = self
        }
    
        func start() {
            let vc = HomeFactory.makeHomeScene(delegate: self)
            navigationController.pushViewController(vc, animated: false)
        }
    }
    
    extension HomeCoordinator: HomeCoordinatorDelegate {
    
        func goToWorkoutCreating() {
            let child = NewRoutineCoordinator(navigationController: navigationController, removeCoordinatorWith: removeChild)
            child.passWorkoutToHomeDelegate = self
            addChild(child: child)
            child.start()
        }

    class NewRoutineCoordinator: NSObject, Coordinator {
    
        var exerciseNumber: Int?
        var childCoordinators = [Coordinator]()
        var navigationController: UINavigationController
        private var removeCoordinatorWhenViewDismissed: ((Coordinator) -> ())
    
        weak var passWorkoutToHomeDelegate: PassWorkoutToHome?
    
        init(navigationController: UINavigationController, removeCoordinatorWith removeCoordinatorWhenViewDismissed: @escaping ((Coordinator) -> ())) {
            self.navigationController = navigationController
            self.removeCoordinatorWhenViewDismissed = removeCoordinatorWhenViewDismissed
        }
  
        func start() {
            navigationController.delegate = self
            let vc = NewRoutineFactory.makeNewRoutineScene(delegate: self)
            navigationController.navigationItem.largeTitleDisplayMode = .never
            navigationController.pushViewController(vc, animated: true)
        }
        
    }

extension NewRoutineCoordinator: UINavigationControllerDelegate {
    
    func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {

        guard let fromViewController = navigationController.transitionCoordinator?.viewController(forKey: .from) else {
            return
        }

        if navigationController.viewControllers.contains(fromViewController) {
            return
        }
        if let vc = fromViewController as? NewRoutineViewController {
            removeCoordinatorWhenViewDismissed(self)
        }
    }
}

        class ExerciseCoordinator: NSObject, Coordinator {
                
            var childCoordinators = [Coordinator]()
            var navigationController: UINavigationController
            
            private var removeCoordinatorWhenViewDismissed: ((Coordinator) -> ())
            
            init(navigationController: UINavigationController, removeCoordinatorWith removeCoordinatorWhenViewDismissed: @escaping ((Coordinator) -> ())) {
                
                self.navigationController = navigationController
                self.removeCoordinatorWhenViewDismissed = removeCoordinatorWhenViewDismissed
            }
        
            func start() {
                navigationController.delegate = self
                let vc = NewExerciseFactory.newExerciseScene(delegate: self)
                navigationController.pushViewController(vc, animated: true)
            }
    
    extension ExerciseCoordinator: UINavigationControllerDelegate {
        func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
    
            guard let fromViewController = navigationController.transitionCoordinator?.viewController(forKey: .from) else {
                return
            }
    
            if navigationController.viewControllers.contains(fromViewController) {
                return
            }
    
            if let vc = fromViewController as? NewExerciseViewController {
                removeCoordinatorWhenViewDismissed(self)
            }
        }
    }

I guess something is nil the second time you navigate back. This often happens to me when I instantiate a view controller inside a function which it gets de-initialized so my delegation doesn't work anymore. What I usually do is declare a variable outside the function and assign the instantiated view controller to it.

For Instance try:

var newRoutineCoordinator: NewRoutineCoordinator?


func goToWorkoutCreating() {
     let child = NewRoutineCoordinator(navigationController: navigationController, removeCoordinatorWith: removeChild)
      newRoutineCoordinator = child
      child.passWorkoutToHomeDelegate = self
      addChild(child: child)
      child.start()
}

Not sure the problem is there but this is just to give you an example.

You have UINavigationControllerDelegate inside an extension of NewRoutineCoordinator but It may be already nil by the time you navigate back.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM