Moving on to the next segue in our storyboard, this time Ben and Soroush tackle the Add Review flow. They discuss naming of delegates, the ideal place to perform logic such as preparing a model to be saved and where mutations to the model live. They end up with a view controller that is completely decoupled from the AddReviewViewController and a better picture of what the coordinator tends to look like.
Episode Links Source Code A little Cleanup The AppCoordinator is starting to take shape, so it's time to move it into its own file. We start by creating AppCoordinator.swift and moving the code into it: // AppCoordinator.swift import UIKit class AppCoordinator : RestaurantsViewControllerDelegate { let navigationController: UINavigationController init(navigationController: UINavigationController) { self.navigationController = navigationController } func start() { let restaurantsVC = navigationController.topViewController as! RestaurantsViewController restaurantsVC.delegate = self } func didSelect(restaurant: Restaurant) { let restaurantDetail = RestaurantViewController.makeFromStoryboard() restaurantDetail.restaurantDelegate = self restaurantDetail.restaurant = restaurant navigationController.pushViewController(restaurantDetail, animated: true) } func addReviewTapped(_ vc: RestaurantViewController) { let storyboard = UIStoryboard(name: "Main", bundle: nil) let nav = storyboard.instantiateViewController(withIdentifier: "AddReviewNavigationController") as! UINavigationController let reviewVC = nav.topViewController as! ReviewViewController reviewVC.addReviewBlock = { [weak self] rvc in let review = Review(author: rvc.nameTextField.text ?? "", comment: rvc.commentTextView.text, rating: Float(rvc.ratingView.value), restaurantID: vc.restaurantID) Restaurants.add(review: review) self?.navigationController.dismiss(animated: true) { vc.insertReview(review) } } navigationController.present(nav, animated: true) } } This can live right next to the AppDelegate.swift in the project organizer. Adding our Next Transition The next transition to handle is the Add Review logic. Currently this is done as a modal transition by the RestaurantViewController. We'll start by removing the segue in the Storyboard. Then we can add the appropriate delegate protocol so the coordinator can handle the actions triggered by this view controller: protocol RestaurantViewControllerDelegate : class { func addReviewTapped(_ vc: RestaurantViewController) } class RestaurantViewController : UITableViewController { weak var restaurantDelegate: RestaurantViewControllerDelegate? // ... } The naming of the property here is slightly awkward because UITableViewController already has a delegate property. Other names we might choose: userActionDelegate, or perhaps coordinationDelegate. Defining the Action Explicitly Using segues we can wire up a transition from a button with no code. Since we don't have segues anymore we need to add an @IBAction for the button tap. We'll just send this off to our restaurantDelegate to handle it. @IBAction func addReview(_ sender: Any) { restaurantDelegate?.addReviewTapped(self) } Comforming to the Protocol Our AppCoordinator will handle these actions, so it will need to conform to this protocol. We can move the code that was previously in our prepare(for segue: sender:) code. class AppCoordinator : RestaurantsViewControllerDelegate, RestaurantViewControllerDelegate { // ... func addReviewTapped(_ vc: RestaurantViewController) { let storyboard = UIStoryboard(name: "Main", bundle: nil) let nav = storyboard.instantiateViewController(withIdentifier: "AddReviewNavigationController") as! UINavigationController let reviewVC = nav.topViewController as! ReviewViewController reviewVC.addReviewBlock = { [weak self] rvc in let review = Review(author: rvc.nameTextField.text ?? "", comment: rvc.commentTextView.text, rating: Float(rvc.ratingView.value), restaurantID: vc.restaurantID) Restaurants.add(review: review) self?.navigationController.dismiss(animated: true) { vc.insertReview(review) } } navigationController.present(nav, animated: true) } } We also need to wire up this delegate: func didSelect(restaurant: Restaurant) { let restaurantDetail = RestaurantViewController.makeFromStoryboard() restaurantDetail.restaurantDelegate = self restaurantDetail.restaurant = restaurant navigationController.pushViewController(restaurantDetail, animated: true) } With this in place we can remove our segue handling code, as this is already implemented in our coordinator. Reviewing What We've Done If you look at the RestaurantViewController now, it is still aware of reviews and the review model, but has no reference whatsoever to the AddReviewViewController. Reducing dependencies in this way can clean up code and make your code more flexible and amenable to change.