I am new to Swift/programing in general and I am trying to become comfortable with the idea of coordinators. Sorry to just dump code but I am just learning.. thanks for any help.
My goal is to launch this app with my ViewController showing up on the screen and this view to have two buttons to go to two other views.
I have defined the following protocols.
import Foundation
import UIKit
protocol CoordinatorProtocol {
var childCoordinators: [CoordinatorProtocol] { get set }
var navigationController: UINavigationController { get set }
func start()
}
and
import Foundation
import UIKit
protocol StoryboardProtocol {
static func instantiate() -> Self
}
extension StoryboardProtocol where Self: UIViewController {
static func instantiate() -> Self {
let id = String(describing: self)
let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
return storyboard.instantiateViewController(withIdentifier: id) as! Self
}
}
I then created my MainCoordinator
import Foundation
import UIKit
class MainCoordinator: CoordinatorProtocol {
var childCoordinators = [CoordinatorProtocol]()
var navigationController: UINavigationController
init(navigationController: UINavigationController) {
self.navigationController = navigationController
}
func start() {
let vc = ViewController.instantiate()
vc.coordinator = self
navigationController.pushViewController(vc, animated: false)
}
func addDisplayOne() {
let vc = ViewOneController.instantiate()
vc.coordinator = self
navigationController.pushViewController(vc, animated: true)
}
func addDisplayTwo() {
let vc = ViewTwoController.instantiate()
vc.coordinator = self
navigationController.pushViewController(vc, animated: true)
}
}
along with my three view controllers
import UIKit
class ViewController: UIViewController, StoryboardProtocol {
weak var coordinator: MainCoordinator?
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func oneTapped(_ sender: Any) {
coordinator?.addDisplayTwo()
}
@IBAction func twoTapped(_ sender: Any) {
coordinator?.addDisplayTwo()
}
}
and
import UIKit
class ViewOneController: UIViewController, StoryboardProtocol {
weak var coordinator: MainCoordinator?
override func viewDidLoad() {
super.viewDidLoad()
}
}
and
import UIKit
class ViewTwoController: UIViewController, StoryboardProtocol {
weak var coordinator: MainCoordinator?
override func viewDidLoad() {
super.viewDidLoad()
}
}
I then updated the appDelegate.Swift with the following and left the rest of the functions as is
var coordinator: MainCoordinator?
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions
launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: Bundle.main)
let initialViewController : UIViewController =
mainStoryboard.instantiateViewController(withIdentifier: "ViewController") as
UIViewController
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
return true
}
I then updated the SceneDelegate.swift with the following and left the rest as is
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
if let controller = UIStoryboard(name: "Main", bundle:
nil).instantiateViewController(withIdentifier: "ViewController") as? ViewController {
if let window = self.window, let rootViewController = window.rootViewController {
var currentController = rootViewController
while let presentedController = currentController.presentedViewController {
currentController = presentedController
}
currentController.present(controller, animated: true, completion: nil)
}
}
}
I have a Main.storyboard which has three view controllers. Each of the view controllers have their class and their storyboardID name as their class name.
All I get is a full black screen when i run the code... makes no sense to me.
A couple of things are wrong here. It's okay, as SceneDelegate.swift was just added recently.
Your main issue here is that in your SceneDelegate's willConnectTo
your if let window = self.window
is nil, thus the rest of your code inside will not get executed resulting to a black screen.
In order to make Coordinator pattern work with storyboard in SceneDelegate.swift add these 2 properties and replace willConnectTo
to the following:
var coordinator: MainCoordinator?
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
let navController = UINavigationController() //create navController
coordinator = MainCoordinator(navigationController: navController) //initialize our coordinator
coordinator?.start() //start coordinator
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = navController //make it our root
window?.makeKeyAndVisible()
window?.windowScene = windowScene
}
Lastly, your AppDelegate.swift's didFinishLaunchingWithOptions
function body does not need anything but return true to implement Coordinator pattern
Feel free to use this as reference: https://github.com/SamuelFolledo/NewsApp/blob/646a005e1be9b90a4c63cb99bf92d5b2be6691cc/NewsApp/SceneDelegate.swift