Brief :
I have implemented Soroush's Coordinators architecture. Everything works fine except the removing part which is needed to remove previous(child) coordinators.
Scenario :
I have two ViewController named HomeViewController and MyGroupsViewController. Each has its own coordinator named HomeCoordinator and MyGroupsCoordinator respectively.
User taps a button on HomeViewController which triggers gotoMyGroupsTapped function and gets the user to MyGroupsViewController, Then the user taps on another button on MyGroupsViewController which get the user back to HomeViewController by triggering gotoHomePage().
Pretty simple! : HomeVC -> MyGroupsVC -> HomeVC
But the Problem is :
navigationController.transitionCoordinator? is nil in func navigationController(..., didShow viewController: UIViewController...) in both coordinators and I can not remove child coordinators in each transition.
Is it correct to set navigationController.delegate = self in start() func of both coordinators?
Should I use navigationController?.popViewController(animated: false ) in my backToHomePage() func? because Paul Hudson has only used pushViewController.
My Codes [Simplified Versions]:
HomeCoordinator.swift
import Foundation
import UIKit
class HomeCoordinator: NSObject,Coordinator,UINavigationControllerDelegate {
var childCoordinators = [Coordinator]()
var navigationController: UINavigationController
weak var parentCoordinator : Coordinator?
init(navigationController: UINavigationController) {
self.navigationController = navigationController
}
func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
// Transition here is nil
print(" Transition : ",navigationController.transitionCoordinator)
guard let fromViewController = navigationController.transitionCoordinator?.viewController(forKey: .from) else {
print("Unknown fromViewController!")
return
}
// Removing a child coordinator
}
func gotoMyGroups (){
let groupsCoordinator = GroupsCoordinator(navigationController: navigationController)
childCoordinators.append(groupsCoordinator)
groupsCoordinator.parentCoordinator = self
groupsCoordinator.start()
}
func start() {
let vc = HomeViewController.instantiate()
vc.coordinator = self
navigationController.delegate = self
navigationController.pushViewController(vc, animated: false)
navigationController.setNavigationBarHidden(true, animated: false)
}
}
MyGroupsCoordinator.swift
import Foundation
import UIKit
class MyGroupsCoordinator: NSObject,Coordinator,UINavigationControllerDelegate {
var childCoordinators = [Coordinator]()
var navigationController: UINavigationController
weak var parentCoordinator : Coordinator?
init(navigationController: UINavigationController) {
self.navigationController = navigationController
}
func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
// Transition here is nil
print(" Transition : ",navigationController.transitionCoordinator)
guard let fromViewController = navigationController.transitionCoordinator?.viewController(forKey: .from) else {
print("Unknown fromViewController!")
return
}
// Removing a child coordinator
}
func start() {
let vc = MyGroupViewController.instantiate()
vc.coordinator = self
navigationController.delegate = self
navigationController.pushViewController(vc, animated: false)
navigationController.setNavigationBarHidden(true, animated: false)
}
}
MyGroupViewController.magik
class MyGroupViewController : UIViewControllerWithCoordinator,UITextFieldDelegate,Storyboarded{
@IBAction func gotoHomePage(_ sender: Any) {
if let coord = coordinator as? GroupsCoordinator {
coord.parentCoordinator?.start()
}
}
}
HomeViewController.swift
class HomeViewController: UIViewControllerWithCoordinator,Storyboarded {
@IBAction func gotoMyGroupsTapped(_ sender: Any) {
guard let acoordinator = coordinator as? HomeCoordinator else {
return
}
acoordinator.gotoMyGroups()
}
It looks to me there is a confusion around Coordinator pattern usage here.
From your expected flow
HomeVC -> MyGroupsVC -> HomeVC, if you mean in the senselevel1 -> level2 -> level3, thenGroupsCoordinatorshould create a newHomeCoordinatorinstance with its own newHomeVC.So instead of your previous code
I would change it to
This will allow you to create a brand new page as you describe there
HomeVC -> MyGroupsVC -> HomeVC.However, if you meant in this approach
level1 -> level2 -> (back) level1, then you'll need to terminateMyGroupsCoordinatorand remove from the parent while navigating back.As you noticed, to do so, you'll need to use
UINavigationControllerDelegateto be able to be notified when the user navigate back (either pop in code, or with classic back button).One solution I found is to use a
Routerto handle all this navigation when aUIViewControlleris removed from it to also notify via closures the right coordinator to be removed. You can read more about it here.Hope it helps