I have been trying to refactor my source code so that it would conform to the Coordinator Pattern. I have used UITabBarController
as the parent viewController of my app which contains 4 viewControllers.
I have been following the tutorials on how to implement the Coordinator pattern for iOS apps, and I have created and set up the protocols and classes of the Coordinator. I have a button inside my viewController (child viewController of the TabbarViewController), however, on button click, coordinator is not pushing / navigating to the desired VC, and I see the coordinator is returning nil
on the debug console while debugging through the breakpoint
, and I could not figure it out how to resolve this issue.
MainCoordinator.swift:
class MainCoordinator: SubCoordinator {
var subCoordinators = [SubCoordinator]()
var navigationController: UINavigationController
init(navigationController: UINavigationController) {
self.navigationController = navigationController
}
func start() {
print("Initialized.. .")
UIApplication.app().window?.rootViewController = self.navigationController
let vc = SplashViewController.instantiate()
vc.coordinator = self
navigationController.pushViewController(vc, animated: false)
}
}
// testing using a simple Viewcontroller class, its background color is set to red, so if the
// navigation works, a blank red VC should appear. but not working so far
func testView() {
let vc = ViewController.instantiate()
vc.coordinator = self
navigationController.pushViewController(vc, animated: false)
}
}
SubCoordinator.swift:
protocol SubCoordinator {
var subCoordinators: [SubCoordinator] { get set }
var navigationController: UINavigationController { get set }
func start()
}
StoryBoarded.swift
:
protocol StoryBoarded {
static func instantiate() -> Self
}
// I am using storyBoard, and `instantiate()` should instantiate and return the specified VC
// from the Storyboard with the specified VC id (?)
extension StoryBoarded where Self: UIViewController {
static func instantiate() -> Self {
let id = String(describing: self)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
return storyboard.instantiateViewController(withIdentifier: id) as! Self
}
}
FirstViewController.Swift:
class FirstViewController: UIViewController, StoryBoarded {
@IBOutlet weak var button: UIButton!
var coordinator: MainCoordinator?
//MARK: - viewDidLoad()
override func viewDidLoad() {
super.viewDidLoad()
// If uncommented the below line, coordinator is not returning `nil`, but not navigating
anyways!
//coordinator = MainCoordinator(navigationController: UINavigationController())
}
@IBAction func onButtonTap(_ sender: Any) {
// So, basically I would expect the coordinator to navigate to the testView, but not
navigating
coordinator?.testView()
}
}
ViewController.swift:
// testView
class ViewController: UIViewController, StoryBoarded {
var coordinator: MainCoordinator?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.view.backgroundColor = .red
}
}
and
// TabbarController, set as the root VC after the splashVC is completed
class MainViewController: UITabBarController, StoryBoarded {
var coordinator: MainCoordinator?
override func viewDidLoad() {
super.viewDidLoad()
let firstVC = UIStoryboard.firstViewController()
let secondVC = UIStoryboard.secondViewController()
let views: [UIViewController] = [firstVC, secondVC]
self.setViewControllers(views, animated: false)
self.navigationController?.navigationBar.isHidden = false
}
}
start()
is being called, and splashVC appears and updates rootViewController with MainViewontroller
on completion, But the navigation is not working at all on button click event.
Any feedback or help would highly be appreciated!
Since you're using the StoryBoarded protocol, you should follow the pattern and call instantiate() for initialization. Then, just set the coordinator.