I am following this tutorial on Coordinator pattern, and so far I have it going through creating the coordinator and running the start() from app delegate. But then calling a function on that coordinator doesn't work, because suddenly the coordinator var is nil. It seems that the initial view controller that is shown is not the one coming from the coordinator.start() but rather the one from the storyboard entry point. I did disable the Main in the main interface of the projects target.
AppDelegate:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
if let registry = DependencyResolver.shared as? DependencyRegistry {
DependencyGraph.setup(for: registry)
}
let navController = UINavigationController()
coordinator = MainCoordinator(navigationController: navController)
coordinator?.start()
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = navController
window?.makeKeyAndVisible()
return true
}
Main coordinator:
class MainCoordinator: Coordinator {
var navigationController: UINavigationController
var childCoordinators = [Coordinator]()
init(navigationController: UINavigationController) {
self.navigationController = navigationController
}
func start() {
let vc = InitViewController.instantiate()
vc.coordinator = self. //!!I do hit this breakpoint
navigationController.pushViewController(vc, animated: false)
}
}
Init view controller (the one that's initial in the storyboard, but I'm showing it with coordinator):
class InitViewController: UIViewController, Storyboarded {
private var cameraViewModel: CameraViewModel!
weak var coordinator: MainCoordinator?
@IBAction func openCameraView(_ sender: Any) {
coordinator?.openCameraView() //!!here coordinator is nil
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
Storyboarded protocol - used to get view controller out of the storyboard by id:
protocol Storyboarded {
static func instantiate() -> Self
}
extension Storyboarded where Self: UIViewController {
static func instantiate() -> Self {
let fullName = NSStringFromClass(self)
let className = fullName.components(separatedBy: ".")[1]
let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
let leController = storyboard.instantiateViewController(withIdentifier: className) as! Self
return leController
}
}
The problem is merely that the tutorial you're looking at is too old for current conditions. There is no Single View App template any more, and the App Delegate no longer contains the window. If you create a project in Xcode 11 or Xcode 12, the window is owned by the scene delegate. Implement the scene delegate's willConnect
method to do the work that the app delegate was doing in the tutorial, and everything will spring to life.
Also the mechanism for preventing Main.storyboard from trying to load automatically has changed; you have to remove it from Application Scene Manifest in the Info.plist (editing by hand — there is no simple interface).