App Coordinators
Overstuffed App Delegate
- (void)setupViewHierarchy { UITabBarController *tabBarVC = (UITabBarController *)self.window.rootViewController; if ([AppConfig isPaidApp]) { [self removeViewControllerOfType:[RRUnlockViewController class] fromTabBarController:tabBarVC]; } if ([AppConfig isMeditationApp]) { if (![AppConfig isPaidApp]) { [self removeViewControllerOfType:[RRFavoriteViewController class] fromTabBarController:tabBarVC]; } RRSoundsViewController *soundsVC = [[UIStoryboard storyboardWithName:@"Sounds" bundle:[NSBundle mainBundle]] instantiateViewControllerWithIdentifier:@"RRSoundsViewController"]; soundsVC.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"Sounds" image:[UIImage imageNamed:@"icon_sounds"] tag:1]; soundsVC.meditationManager = self.meditationManager; UINavigationController *soundsNVC = [[UINavigationController alloc] initWithRootViewController:soundsVC]; RRTimerViewController *timerVC = [[UIStoryboard storyboardWithName:@"Timer" bundle:[NSBundle mainBundle]] instantiateViewControllerWithIdentifier:@"RRTimerViewController"]; timerVC.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"Timer" image:[UIImage imageNamed:@"icon_timer"] tag:1]; timerVC.timerManager = self.timerManager; UINavigationController *timerNVC = [[UINavigationController alloc] initWithRootViewController:timerVC]; NSMutableArray *allViewControllers = [tabBarVC.viewControllers mutableCopy]; [allViewControllers insertObject:soundsNVC atIndex:0]; [allViewControllers insertObject:timerNVC atIndex:3]; tabBarVC.viewControllers = allViewControllers;
. . .
Too Many Responsibilities
Model Domain State & Behavior
View Controller
Mediates Model-View Interactions
View
Display & Layout
View Controller
Model-View Binding
View Controller
Model-View Binding Subview Allocation
View Controller
Model-View Binding Subview Allocation Data Fetching
View Controller
Model-View Binding Subview Allocation Data Fetching
View Controller
Layout
Model-View Binding Subview Allocation Data Fetching
View Controller
Layout Data Transformation
Model-View Binding Subview Allocation Data Fetching
View Controller
Layout Data Transformation Navigation Flow
Model-View Binding Subview Allocation Data Fetching
View Controller
Layout Data Transformation Navigation Flow
User Input
Model-View Binding Subview Allocation Data Fetching
View Controller
Layout Data Transformation Navigation Flow
User Input Model Mutation
Navigation Flow
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let photo = self.data[indexPath.row]
let nextViewController = PhotosViewController(with: photo)
self.navigationController?.pushViewController(nextViewController) }
LoginViewController
PhotosViewController
NewPhotoViewController
SavePhotoViewController
Libraries
Frameworks
Libraries
Frameworks
you call
Libraries
Frameworks
you call
call you
App Coordinatoraka Application Controller, Flow Controller
What does a coordinator do?
Model-View Binding Subview Allocation Data Fetching
View Controller
Layout Data Transformation Navigation Flow
User Input Model Mutation
App Coordinator
View Model
Model-View Binding
Subview Allocation
Data Fetching
View Controller
Layout Data Transformation Navigation Flow
User Input Model Mutation
App Coordinator
View Model
Model-View Binding
Subview Allocation
Data Fetching
View Controller
Layout
Data Transformation Navigation Flow
User Input Model Mutation
App Coordinator
View Model
Model-View Binding
Subview Allocation
Data Fetching
View Controller
Layout
Data Transformation
Navigation Flow
User Input Model Mutation
App Coordinator
View Model
Model-View Binding
Subview Allocation
Data Fetching
View Controller
Layout
Data Transformation
Navigation Flow
User Input Model Mutation
App Coordinator
View Model
Model-View Binding
Subview Allocation
Data Fetching
View Controller
Layout
Data Transformation
Navigation Flow
User Input
Model Mutation
App Coordinator
View Model
Model-View Binding
Subview Allocation
Data Fetching
View Controller
Layout
Data Transformation
Navigation Flow
User Input
Model Mutation
App Coordinator
View Model
How to use coordinators?
let dependencies = Dependencies(api: vidmeApi, persistenceManager: realmDB) appCoordinator = AppCoordinator(window: window!, dependencies: dependencies) appCoordinator.start()
class AppCoordinator: Coordinator { private let window: UIWindow private let dependencies: Dependencies private var childCoordinators = [Coordinator]()
func start() { if isLoggedIn {
showContent() } else { showAuth() }
} }
func showAuth() { let loginCoordinator = LoginCoordinator(navigationController: self.navigationController,
dependencies: self.dependencies)
loginCoordinator.delegate = self
self.childCoordinators.append(loginCoordinator)
loginCoordinator.start() }
class LoginCoordinator: Coordinator {
func start() { let loginViewController = LoginViewController() loginViewController.api = dependencies.api loginViewController.persistenceManager = dependencies.persistenceManager loginViewController.delegate = self navigationController.pushViewController(loginViewController, animated: true)
} func loginViewController(viewController: LoginViewController, didLoginUser user: User) {
delegate?.userDidLogin(user) } }
Why coordinators are great?
1. View Controllers are isolated
A B C D
A B C D
Coordinator
1. View Controllers are isolated
1. View Controllers are isolated
2. View Controllers are reusable
1. View Controllers are isolated
2. View Controllers are reusable
3. Every task is encapsulated
1. View Controllers are isolated
2. View Controllers are reusable
3. Every task is encapsulated
4. Coordinators are fully in our control
Thanks 🌞