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
, thenGroupsCoordinator
should create a newHomeCoordinator
instance 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 terminateMyGroupsCoordinator
and remove from the parent while navigating back.As you noticed, to do so, you'll need to use
UINavigationControllerDelegate
to 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
Router
to handle all this navigation when aUIViewController
is removed from it to also notify via closures the right coordinator to be removed. You can read more about it here.Hope it helps