Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Coordinators and memory management

Coordinators and memory management

A talk given at Cocoaheads Lille in April 2018.

Charles-Henri DUMALIN

April 19, 2018
Tweet

Other Decks in Programming

Transcript

  1. We all have this ViewController → Layout → View State

    management → Data fetching & persistance → Navigation
  2. Why is this? → ViewController have an unclear role in

    UIKit → Apple's vision of MVC is not matching our needs
  3. Why does this not match our expectations? → Apple expects

    us to do a local first app with CoreData → In this context their architecture makes perfect sense
  4. Remember our ViewController? → Layout: UIView → View State management:

    UIViewController → Data fetching & persistance: ViewModel → Navigation: ????
  5. What does a Coordinator do? → Manages the navigation flow

    → Instanciates the controllers and injects dependencies
  6. How does it do it? → It's a plain Swift

    object → You do what you want with it → You just implement the Coordinator Protocol → You use delegation (or Reactive Programming) at the controller level
  7. class AppCoordinator { let window: UIWindow let navigationController: UINavigationController! let

    homeController: HomeViewController! init(window: UIWindow) { self.window = window } } extension AppCoordinator: Coordinator { func start(animated: Bool) { homeController = HomeViewController.instanciateFromStoryboard() navigationController = UINavigationController(root: homeController) window.rootViewController = navigationController window.makeKeyAndVisible() } }
  8. class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? var coordinator:

    Coordinator! func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]? ) -> Bool { let window = UIWindow(frame: UIScreen.main.bounds) coordinator = AppCoordinator(window: window) coordinator.start(animated: false) self.window = window } }
  9. class DetailCoordinator { let navigationController: UINavigationController let detailController: DetailViewController init(_

    navigationController: UINavigationController) { self.navigationController = navigationController } } extension DetailCoordinator: Coordinator { func start(animated: Bool) { let detailController = DetailViewController.instanciateFromStoryboard() navigationController.pushViewController(detailController, animated: animated) } }
  10. class AppCoordinator { let window: UIWindow let navigationController: UINavigationController! let

    homeController: HomeViewController! var childCoordinator: Coordinator? init(window: UIWindow) { self.window = window } } extension AppCoordinator: Coordinator { func start(animated: Bool) { homeController = HomeViewController.instanciateFromStoryboard() homeController.delegate = self navigationController = UINavigationController(root: homeController) window.rootViewController = navigationController window.makeKeyAndVisible() } } extension AppCoordinator: HomeControllerDelegate { func didTouchDetailButton() { let coordinator = DetailCoordinator(_ navigationController: navigationController) coordinator.start() childCoordinator = coordinator } }
  11. What's the problem here ? → UIKit creates a strong

    reference → But Coordinator should own it... → UIKit decides when the view is released
  12. ! How do I let the parent Coordinator know that

    the Coordinator is not needed anymore?
  13. The lifecycle probe → When the ViewController is deallocated it

    sends a message to the Coordinator → The Coordinator sends a message to its parent to be released
  14. Yui streamlines the process → Conform to the protocol →

    Follow the guidelines → You're done !