StoryboardController: A storyboard controller manages a set of view controllers described in a storyboard file that make up a portion of your app’s user interface. A storyboard controller is to a storyboard what a view controller is to a view. Whereas a view controller would manage a view heirachy that allows a user to perform a single task, a s…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// StoryboardController.h | |
// Ideas | |
// | |
// Created by James Moschou on 12/3/13. | |
// Copyright (c) 2013 James Moschou. All rights reserved. | |
// | |
#import <Foundation/Foundation.h> | |
@protocol StoryboardControllerDelegate; | |
/** | |
A storyboard controller manages a set of view controllers described in a | |
storyboard file that make up a portion of your app’s user interface. | |
A storyboard controller is to a storyboard what a view controller is to a view. | |
Whereas a view controller would manage a view heirachy that allows a user to | |
perform a single task, a storyboard controller would manage a set of view | |
controllers that make up a single flow. For example, in the creation of a | |
complex model object, the app may guide the user through a series of optional | |
stages, each associated with a different view controller; a storyboard | |
controller encapsulates this flow and can provide a common interface through | |
which to be notified the flow has finished. | |
*/ | |
@interface StoryboardController : NSObject | |
- (instancetype)initWithStoryboardName:(NSString *)storyboardNameOrNil bundle:(NSBundle *)storyboardBundleOrNil; | |
@property (nonatomic, readonly, copy) NSString *storyboardName; | |
@property (nonatomic, readonly, strong) NSBundle *storyboardBundle; | |
- (void)storyboardDidLoad; | |
@property (nonatomic, readonly, strong) UIStoryboard *storyboard; | |
@property (nonatomic, weak) id <StoryboardControllerDelegate> delegate; | |
/** Displays the storyboard. | |
To use this method, you must first provide a delegate object that implements | |
the storyboardControllerViewControllerForPresentation: method. The view | |
controller returned by that method is used to present the storyboard modally. | |
@param animated Specify YES to animate the appearance of the storyboard or NO | |
to display it immediately. | |
*/ | |
- (void)presentStoryboardAnimated:(BOOL)animated; | |
/** Displays the storyboard and anchors it to the specified location in the | |
view. | |
@param rect The rectangle in view at which to anchor the storyboard. | |
@param view The view containing the anchor rectangle for the | |
storyboard. | |
@param arrowDirections The arrow directions the storyboard is permitted to use. | |
@param animated Specify YES to animate the presentation of the | |
storyboard or NO to display it immediately. | |
*/ | |
- (void)presentStoryboardFromRect:(CGRect)rect inView:(UIView *)view permittedArrowDirections:(UIPopoverArrowDirection)arrowDirections animated:(BOOL)animated; | |
/** Displays the storyboard and anchors it to the specified bar button item. | |
When presenting the storybaord, this method adds the toolbar that owns the | |
button to the storyboard's list of passthrough views. Thus, taps in the toolbar | |
result in the action methods of the corresponding toolbar items being called. | |
If you want the storyboard to be dismissed when a different toolbar item is | |
tapped, you must implement that behavior in your action handler methods. | |
@param item The bar button item on which to anchor the storyboard. | |
@param arrowDirections The arrow directions the storyboard is permitted to use. | |
@param animated Specify YES to animate the presentation of the | |
storyboard or NO to display it immediately. | |
*/ | |
- (void)presentStoryboardFromBarButtonItem:(UIBarButtonItem *)item permittedArrowDirections:(UIPopoverArrowDirection)arrowDirections animated:(BOOL)animated; | |
/** Dismisses the storyboard programmatically. | |
You can use this method to dismiss the storyboard programmatically in response | |
to taps inside the storyboard window. Taps outside of the storyboard's contents | |
automatically dismiss the storyboard. | |
@param animated Specify YES to animate the dismissal of the storyboard or NO to | |
dismiss it immediately. | |
*/ | |
- (void)dismissStoryboardAnimated:(BOOL)animated; | |
@end | |
@protocol StoryboardControllerDelegate <NSObject> | |
/** Called when a storyboard controller needs a view controller for presenting a | |
storyboard. | |
This method is required if your application attempts to display a storyboard. | |
The view controller returned by this method is used as the parent for the | |
storyboard. | |
If you return a navigation controller from this method, the inital view | |
controller of the storyboard controller is pushed onto the navigation stack | |
using the standard navigation controller animations. If you return any other | |
type of view controller, the storyboard controller is displayed modally, in | |
which case, the view controller you return must be capable of presenting a | |
modal view controller. | |
@param storyboardController The storyboard controller requesting the parent | |
view controller. | |
@return The view controller to user when presenting the storyboard. The return | |
value must not be nil. | |
*/ | |
- (UIViewController *)storyboardControllerViewControllerForPresentation:(StoryboardController *)storyboardController; | |
/** Called when a storyboard controller needs to instantiate a view controller | |
from its storyboard for the first time. | |
If this method is not implemented or returns nil, the storyboard view | |
controller will instantiate the view controller using | |
instantiateInitialViewController. | |
@param storyboardController The storyboard controller requesting the identifier | |
for the view controller to instantiate. | |
@return A string specifying the identifer for the view controller to | |
instantiate from the storyboard first. | |
*/ | |
- (NSString *)storyboardControllerIdentifierForInitialViewController:(StoryboardController *)storyboardController; | |
@end | |
@interface UIViewController (StoryboardController) | |
@property (nonatomic, readonly, strong) StoryboardController *presentedStoryboardController; | |
- (void)presentStoryboardController:(StoryboardController *)storyboardControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion; | |
- (void)dismissStoryboardControllerAnimated:(BOOL)flag completion:(void (^)(void))completion; | |
@end | |
@interface UIStoryboard (StoryboardController) | |
@property (nonatomic, weak) StoryboardController *controller; | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// StoryboardController.m | |
// Ideas | |
// | |
// Created by James Moschou on 12/3/13. | |
// Copyright (c) 2013 James Moschou. All rights reserved. | |
// | |
#import <objc/runtime.h> | |
#import "StoryboardController.h" | |
@interface StoryboardController () | |
@property (nonatomic, readwrite, weak) UIViewController *presentingViewController; | |
@end | |
@implementation StoryboardController | |
- (instancetype)initWithStoryboardName:(NSString *)storyboardNameOrNil bundle:(NSBundle *)storyboardBundleOrNil | |
{ | |
self = [super init]; | |
if (self) { | |
_storyboardName = [storyboardNameOrNil copy]; | |
_storyboardBundle = storyboardBundleOrNil; | |
} | |
return self; | |
} | |
- (UIStoryboard *)storyboard | |
{ | |
if (!_storyboard) { | |
[self loadStoryboard]; | |
[self storyboardDidLoad]; | |
NSAssert(_storyboard, @"self.storyboard must not be nil after calling -loadStoryboard."); | |
} | |
return _storyboard; | |
} | |
- (void)loadStoryboard | |
{ | |
NSString *name = self.storyboardName ?: NSStringFromClass([self class]); | |
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:name bundle:self.storyboardBundle]; | |
if (!storyboard && [name hasSuffix:@"Controller"]) { | |
storyboard = [UIStoryboard storyboardWithName:[name substringToIndex:name.length - @"Controller".length] bundle:self.storyboardBundle]; | |
} | |
storyboard.controller = self; | |
self.storyboard = storyboard; | |
} | |
- (void)storyboardDidLoad | |
{ | |
} | |
@end | |
@interface UIViewController (StoryboardControllerPrivate) | |
@property (nonatomic, readwrite, strong) StoryboardController *presentedStoryboardController; | |
@end | |
@implementation UIViewController (StoryboardController) | |
- (void)presentStoryboardController:(StoryboardController *)storyboardControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion | |
{ | |
NSAssert(!self.presentedViewController, @"Cannot present a storyboard controller while a view controller is already presented."); | |
NSString *initialViewControllerIdentifier; | |
UIViewController *initialViewController; | |
if ([storyboardControllerToPresent.delegate respondsToSelector:@selector(storyboardControllerIdentifierForInitialViewController:)]) { | |
initialViewControllerIdentifier = [storyboardControllerToPresent.delegate storyboardControllerIdentifierForInitialViewController:storyboardControllerToPresent]; | |
} | |
if (initialViewControllerIdentifier) { | |
initialViewController = [storyboardControllerToPresent.storyboard instantiateViewControllerWithIdentifier:initialViewControllerIdentifier]; | |
} else { | |
initialViewController = [storyboardControllerToPresent.storyboard instantiateInitialViewController]; | |
} | |
[self presentViewController:initialViewController animated:flag completion:^{ | |
self.presentedStoryboardController = storyboardControllerToPresent; | |
storyboardControllerToPresent.presentingViewController = self; | |
if (completion) completion(); | |
}]; | |
} | |
- (void)dismissStoryboardControllerAnimated:(BOOL)flag completion:(void (^)(void))completion | |
{ | |
[self dismissViewControllerAnimated:flag completion:completion]; | |
} | |
@end | |
@implementation UIStoryboard (StoryboardController) | |
static void *StoryboardControllerKey = &StoryboardControllerKey; | |
- (StoryboardController *)controller | |
{ | |
return objc_getAssociatedObject(self, StoryboardControllerKey); | |
} | |
- (void)setController:(StoryboardController *)storyboardController | |
{ | |
objc_setAssociatedObject(self, StoryboardControllerKey, storyboardController, OBJC_ASSOCIATION_ASSIGN); | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment