Bob McCuneAbout...
‣MN Developer and Instructor‣Owner of TapHarmonic, LLC.‣Founded Minnesota CocoaHeads in 2008
What will I learn?Agenda
‣View Controller Overview‣Custom Containers Before iOS 5‣ iOS 5’s View Controller Containment API‣Custom Container Demo
View ControllerOverview
View Controller OverviewWhat is a View Controller?
‣Focal point of most iOS app development‣Key Responsibilities:‣De!nes the application work"ow‣Manages a view hierarchy‣ Programmatically
‣ NIB and/or Storyboard
‣Plays the MVC “Controller” role...
View Controller: The “C” in MVCUnderstanding MVC
Controller
View
User ActionsUpdate State
Model
View Controller: The “C” in MVCUnderstanding MVC
Controller
View
Update UIState Changed
Model
Core iOS Design PatternMVC Bene!ts
‣Clean separation of concerns‣Simpli!es development‣Provides for greater reusability‣ Improves quality
‣Allows us to standardize the behavior and responsibilities at each tier
Standardized BehaviorUIViewController Lifecycle
‣ Rotation Callbacks- (void)willRotateToInterfaceOrientation:- (void)willAnimateRotationToInterfaceOrientation:- (void)didRotateFromInterfaceOrientation:
‣ Loading Callbacks- (void)viewDidLoad;- (void)viewDidUnload;
‣ Appearance Callbacks- (void)viewWillAppear:- (void)viewDidAppear:- (void)viewWillDisappear:- (void)viewDidDisappear:
Container vs ContentView Controller Types
Container Controllers‣ Manages a hierarchy of child view controllersUITabBarControllerUINavigationControllerUISplitViewController
Content Controllers‣ Manage the individual screens within an app‣ Can be used in multiple presentation contexts‣ Manages a “screenful of content”
Seems reasonable...Screenful of Content
Still reasonable?Screenful of Content
What’s a screenful?UISplitViewController
One Screen, Multiple ControllersWhy Create Custom Containers?
‣Aesthetics‣Create a custom application "ow
Custom ContainersThe heartbreaking true story
Pre - iOS 5
Faulty AssumptionsCustom Containers
Static Logo
Faulty AssumptionsCustom Containers
Static Logo
Faulty AssumptionsCustom Containers
Static Logo
Faulty AssumptionsCustom Containers
Static Logo
No you can’t!
Custom Container FailWhat’s the problem?
‣Broken View Controller Hierarchy
‣ Rotation Callbacks- (void)willRotateToInterfaceOrientation:- (void)willAnimateRotationToInterfaceOrientation:- (void)didRotateFromInterfaceOrientation:
‣ Appearance Callbacks- (void)viewWillAppear:- (void)viewDidAppear:- (void)viewWillDisappear:- (void)viewDidDisappear:
Ugly OptionsHow do you !x it?
Create a MonstrosityControllerNot practical
Create non-UIViewController controllersNot scalable
Create container and forward callbacksIncomplete and ugly
View Controller Containment
View vs View ControllerObject Hierarchies
Window
Root View
Tab Bar
NavBar
Segmented
View Hierarchy
View vs View ControllerObject Hierarchies
View Controller Hierarchy
UITabBarController
UINavigationController
ContentViewController
Simple, but subtleView Controller Containment
Child View Controller Callbacks- (void)willMoveToParentViewController:(UIViewController *)parent;- (void)didMoveToParentViewController:(UIViewController *)parent;
Adding and removing child controllers- (void)addChildViewController:(UIViewController *)controller;- (void)removeFromParentViewController;
Accessing the children@property(nonatomic,readonly) NSArray *children;
Adding a Child View ControllerContainment API Usage
[self addChildViewController:controller];[self.view addSubview:controller.view];[controller didMoveToParentViewController:self];
ParentViewController
ChildViewController view
view
willMove
Adding a Child View ControllerContainment API Usage
[self addChildViewController:controller];[self.view addSubview:controller.view];[controller didMoveToParentViewController:self];
ParentViewController
ChildViewController view
view
didMove
Adding a Child View ControllerContainment API Usage
[self addChildViewController:controller];[self.view addSubview:controller.view];[controller didMoveToParentViewController:self];
ParentViewController
ChildViewController view
view
willMove
Removing a Child View ControllerContainment API Usage
ParentViewController
ChildViewController view
view
[controller willMoveToParentViewController:nil];[controller.view removeFromSuperview];[controller removeFromParentViewController];
Removing a Child View ControllerContainment API Usage
ParentViewController
ChildViewController view
view
[controller willMoveToParentViewController:nil];[controller.view removeFromSuperview];[controller removeFromParentViewController];
didMove
Removing a Child View ControllerContainment API Usage
ParentViewController
ChildViewController view
view
[controller willMoveToParentViewController:nil];[controller.view removeFromSuperview];[controller removeFromParentViewController];
Simplifying TransitionsView Controller Transitions
- (void)transitionFromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))block;
‣ Convenience method for view controller transitions‣Optional, but simpli!es and normalizes transitioning
- (void)pushViewController:(UIViewController *)toViewController animated:(BOOL)animated {
UIViewController *fromViewController = [self.stack topObject]; toViewController.view.frame = CGRectMake(width, 0.f, width, height);
[self addChildViewController:toViewController];
NSTimeInterval duration = animated ? 0.3f : 0.f;
[self transitionFromViewController:fromViewController toViewController:toViewController duration:duration options:UIViewAnimationCurveEaseInOut animations:^{ CGRect frame = CGRectMake(-width, 0.f, width, height); fromViewController.view.frame = frame; } completion:^(BOOL complete) { [toViewController didMoveToParentViewController:self]; [self.stack pushObject:toViewController]; }];}
pushViewController:animated:Cloning UINavigationController
popViewControllerAnimated:Cloning UINavigationController
- (UIViewController *)popViewControllerAnimated:(BOOL)animated {
UIViewController *fromViewController = [self.stack popObject]; UIViewController *toViewController = [self.stack topObject];
[fromViewController willMoveToParentViewController:nil];
NSTimeInterval duration = animated ? 0.3f : 0.0f;
[self transitionFromViewController:fromViewController toViewController:toViewController duration:duration options:UIViewAnimationOptionCurveEaseInOut animations:^{ CGRect frame = CGRectMake(width, 0.f, width, height); fromViewController.view.frame = frame; } completion:^(BOOL complete) { [fromViewController removeFromParentViewController]; }]; return fromViewController;}
Fine Tuning ContainmentDisabling Auto Forwarding
- (BOOL)automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers { return NO;}
• Control timing of appearance and rotation callbacks• Useful override in complex containment scenarios
Common MistakesAvoiding
Simple API, Common ProblemsCommon Mistakes
‣Outside Callers‣Disobedient Children‣Meddling Parents
Drive-by AdoptionOutside Callers
ModalViewController
ChildViewController
RootViewController
- (IBAction)showModalView:(id)sender { ModalViewController *modalController = [ModalViewController controller]; [self presentViewController:modalController animated:YES completion:nil]; ChildViewController *childController = [ChildViewController controller]; [modalController addChildViewController:childController]; [modalController addSubview:childController.view];}
Parents make the rulesDisobedient Children
- (void)showChildViewController:(UIViewController *)controller { [self addChildViewController:controller];
CustomContainerController
CustomContainerController
OtherViewController
controller.view.frame = CGRectMake(0, 0, 320, 480); [self.view addSubview:controller.view]; [controller didMoveToParentViewController:self];}
- (void)didMoveToParentViewController:(UIViewController *)parent { self.view.frame = CGRectMake(0, 260, 320, 220); [parent.view addSubview:self.view];}
ChildViewController
ChildViewController
Parents make the rulesDisobedient Children
- (void)showChildViewController:(UIViewController *)controller { [self addChildViewController:controller];
CustomContainerController
CustomContainerController
OtherViewController
controller.view.frame = CGRectMake(0, 0, 320, 480); [self.view addSubview:controller.view]; [controller didMoveToParentViewController:self];}
- (void)didMoveToParentViewController:(UIViewController *)parent { self.view.frame = CGRectMake(0, 260, 320, 220); [parent.view addSubview:self.view];}
ChildViewController
ChildViewController
Parents make the rulesDisobedient Children
- (void)showChildViewController:(UIViewController *)controller { [self addChildViewController:controller];
CustomContainerController
OtherViewController
CustomContainerController
[controller didMoveToParentViewController:self];}
ChildViewController
controller.view.frame = CGRectMake(0, 260, 320, 220); [self.view addSubview:controller.view];
Let children be childrenMeddling Parents
ParentViewController
ChildViewController
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)orientation duration:(NSTimeInterval)duration { self.childViewController.button1.frame = // button 1 frame for orientation; self.childViewController.button2.frame = // button 2 frame for orientation; self.childViewController.button3.frame = // button 3 frame for orientation;}
ParentViewController
Let children be childrenMeddling Parents
ParentViewController
ChildViewController
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)orientation duration:(NSTimeInterval)duration { self.button1.frame = // button 1 frame for orientation; self.button2.frame = // button 2 frame for orientation; self.button3.frame = // button 3 frame for orientation;}
ChildViewController
Let children be childrenMeddling Parents
ParentViewController
ChildViewController
Demo
View Controller Containment FTW!Summary
‣Simple, but subtle API. Easy to make mistakes.‣Need to understand UIViewController internals‣Small, but important, enhancements in iOS 6
Resources
Presentation Materialshttp://www.slideshare.net/bobmccune/https://github.com/tapharmonic/
WWDC 2011: Implementing View Controller Containmenthttps://developer.apple.com/videos/wwdc/2011/?id=102
WWDC 2012: The Evolution of View Controllers on iOShttps://developer.apple.com/videos/wwdc/2012/?id=236
BobMcCune.com @bobmccune
Top Related