container viewcontrollers versus single custom viewcontrollers on iPad app - xcode

I am converting an existing iPhone app for the iPad app. The iPhone app was built using a container viewcontroller (UINavigationController) which presented the user first with a custom viewcontroller (UITableViewController) that pushed a custom viewcontroller (UIViewController) based on row selection.
In the iPad app, I am presenting the user directly with the custom UIViewController (with NO container controller) and then allow selection of different options via a UIPopoverController. In myAppDelegate.m I am simply adding the custom UIViewController to the window using:
[window addSubview:[myCustomViewController view]];
In myCustomViewController.m I am modifying the view heavily based upon device rotation by registering for orientation change notifications in viewWillAppear:
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(didRotate:) name:#"UIDeviceOrientationDidChangeNotification" object:nil];
}
I am then testing the orientation in the didRotate: method and getting very strange results. It is being called three times simply loading the view? It also seems to be reporting the orientation corresponding to the PREVIOUS drawing of the view?
- (void) didRotate:(NSNotification *)notification
{
if (self.interfaceOrientation == UIInterfaceOrientationPortrait) {
NSLog(#"Portrait");
} else if (self.interfaceOrientation == UIInterfaceOrientationLandscapeLeft || self.interfaceOrientation == UIInterfaceOrientationLandscapeRight) {
NSLog(#"Landscape");
}
}
I was reading in the docs and it appears that adding the subview to the window (without a container class) will not cause viewWillAppear: method to be called, but in my case it seems it is being called, just unreliably.
Is there some other pattern I should be using for this app? I simply want to load a single custom view and use two popover controllers (no other navigation)?
-Derrick
btw - It works exactly as it should if I push the custom viewController onto a UINavigationController in my app delegate. I just don't need a nav controller for this app.

In my app I'm working on, I first have a property to find out if the device is an iPad:
- (BOOL)iPad {
return UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad ? YES : NO;
}
And then you can use the following delegate method of your view.
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
if (self.iPad) {
if (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft ||
toInterfaceOrientation == UIInterfaceOrientationLandscapeRight) {
//do some stuff
}
}
Hope this helps.

Related

The new UISplitViewController in iOS8 using objective c without storyboard

I try to implement adaptive UI in my app. By making UISplitViewController as the rootview controller, I can run the iPhone's code in iPad too.
I red Apple's documentation about UISplitViewController and some samples. All are using storyboards and the sample codes are available in swift only. I can not find a working version of code. So I started the code myself.
See my splitview controller class (BaseSplitViewController)
BaseSplitViewController.h:
#import <UIKit/UIKit.h>
#interface BaseSplitViewController : UISplitViewController <UISplitViewControllerDelegate>
#end
BaseSplitViewController.m:
#import "BaseSplitViewController.h"
#import "TabBarViewController.h"
#interface BaseSplitViewController ()
#property(nonatomic, strong) TabBarViewController *primaryTabBarVC;
#property(nonatomic, strong) UINavigationController *primaryNavigationController;
#property(nonatomic, strong) UINavigationController *secondaryNavigationController;
#end
#implementation BaseSplitViewController
- (instancetype)init
{
self = [super init];
if (self)
{
[self setViewControllers:#[self.primaryNavigationController, self.secondaryNavigationController]];
self.delegate = self;
self.preferredDisplayMode = UISplitViewControllerDisplayModeAutomatic;
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(cellTapped:) name:#"cellTapped" object:nil];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self assignPrimaryViewController];
}
- (void)assignPrimaryViewController
{
// Need to assign tab bar controller as primary view controller here
}
- (void)assignSecondaryViewController:(UIViewController *)vc
{
// Need to update the secondary controller each time the primary controller was tapped
}
- (UINavigationController *)primaryNavigationController
{
if (!_primaryNavigationController)
{
_primaryNavigationController = [[UINavigationController alloc] init];
}
return _primaryNavigationController;
}
- (UINavigationController *)secondaryNavigationController
{
if (!_secondaryNavigationController)
{
_secondaryNavigationController = [[UINavigationController alloc] init];
}
return _secondaryNavigationController;
}
- (UITabBarController *)primaryTabBarVC
{
if (!_primaryTabBarVC)
{
_primaryTabBarVC = [[TabBarViewController alloc] init];
}
return _primaryTabBarVC;
}
#end
Some points:
The above class "BaseSplitViewController" is the rootview controller of my app.
That is, self.window.rootViewController = [[BaseSplitViewController alloc] init];
From Apple's Documentation,
"When designing your split view interface, it is best to install
primary and secondary view controllers that do not change. A common
technique is to install navigation controllers in both positions and
then push and pop new content as needed. Having these types of anchor
view controllers makes it easier to focus on your content and let the
split view controller apply its default behavior to the overall
interface."
So, I created two navigation controllers (primary/secondary) and set them as split view controllers's primary & secondary views. setViewControllers: can be used for this.
My primary view here is, tab bar view. So, inside the assignPrimaryViewController: method, I should assign my TabBarViewController as split view controller's primary view.
Here, I found two ways.
1. [self.primaryNavigationController showViewController:self.primaryTabBarVC sender:nil];
2. [self.primaryNavigationController pushViewController:self.primaryTabBarVC animated:YES];
Here, I tried with [self showViewController:self.primaryTabBarVC sender:nil]; but my tab bar view was never shown. From my understanding, here "self" means the UISplitViewController. Calling showViewController: here makes the confusion to choose the navigation controller. Because we have two navigation controllers. So we need to clearly tell that navigation controller which needs to hold the primary controller.
Primary view controller part is over. Now the real problem starts. Consider my primary view controller is the tab bar which have tableview's in it. If I tap on the cell, I need to update the secondary view's content. This is the case in Regular mode. In compact mode, I expect when the user taps on the cell, it should push the detail view (secondary view) with back button.
I expect to put the below code within assignSecondaryViewController: vc: method
[self.secondaryNavigationController pushViewController:vc animated:NO];
[self.primaryNavigationController showDetailViewController:self.secondaryNavigationController sender:nil];
But it does not works.
Questions:
What should be placed inside assignPrimaryViewController & assignSecondaryViewController: methods to get my expected result?
And I really, yes really don't know how to implement UISplitViewController's following delegate methods.
primaryViewControllerForCollapsingSplitViewController:
splitViewController:collapseSecondaryViewController:ontoPrimaryViewController:
primaryViewControllerForExpandingSplitViewController:
splitViewController:separateSecondaryViewControllerFromPrimaryViewController:
Would be really helpful, if someone explains this new UISplitViewController's behavior.
Thanks

Cocoa Storyboard Responder Chain

Storyboards for Cocoa apps seems like a great solution as I prefer the methodology you find in iOS. However, while breaking things up into separate view controllers makes a lot of logical sense, I'm not clear as to how to pass window control (toolbar buttons) or menu interaction down to the view controllers that care. My app delegate is the first responder and it receives the the menu or toolbar actions, however, how can I access the view controller that I need to get that message to? Can you just drill down into the view controllers hierarchy. If so, how do you get there from the app delegate since it's the first responder? Can you make the window controller the first responder instead. If so, how? In the storyboard? Where?
Since this is a high level question it may not matter, however, I am using Swift for this project if you're wondering.
I'm not sure if there is a "proper" way to solve this, however, I have come up with a solution that I'll use for now. First a couple of details
My app is a document based application so each window has an instance of the document.
The document the app uses can act as the first responder and forward any actions I've connected
The document is able to get a hold of the top level window controller and from there I am able to drill down through the view controller hierarchy to get to the view controller I need.
So, in my windowDidLoad on the window controller, I do this:
override func windowDidLoad() {
super.windowDidLoad()
if self.contentViewController != nil {
var vc = self.contentViewController! as NSSplitViewController
var innerSplitView = vc.splitViewItems[0] as NSSplitViewItem
var innerSplitViewController = innerSplitView.viewController as NSSplitViewController
var layerCanvasSplitViewItem = innerSplitViewController.splitViewItems[1] as NSSplitViewItem
self.layerCanvasViewController = layerCanvasSplitViewItem.viewController as LayerCanvasViewController
}
}
Which gets me the view controller (which controls the view you see outlined in red below) and sets a local property in the window view controller.
So now, I can forward the toolbar button or menu item events directly in the document class which is in the responder chain and therefore receives the actions I setup in the menu and toolbar items. Like this:
class LayerDocument: NSDocument {
#IBAction func addLayer(sender:AnyObject) {
var windowController = self.windowControllers[0] as MainWindowController
windowController.layerCanvasViewController.addLayer()
}
// ... etc.
}
Since the LayerCanvasViewController was set as a property of the main window controller when it got loaded, I can just access it and call the methods I need.
For the action to find your view controllers, you need to implement -supplementalTargetForAction:sender: in your window and view controllers.
You could list all child controllers potentially interested in the action, or use a generic implementation:
- (id)supplementalTargetForAction:(SEL)action sender:(id)sender
{
id target = [super supplementalTargetForAction:action sender:sender];
if (target != nil) {
return target;
}
for (NSViewController *childViewController in self.childViewControllers) {
target = [NSApp targetForAction:action to:childViewController from:sender];
if (![target respondsToSelector:action]) {
target = [target supplementalTargetForAction:action sender:sender];
}
if ([target respondsToSelector:action]) {
return target;
}
}
return nil;
}
I had the same Storyboard problem but with a single window app with no Documents. It's a port of an iOS app, and my first OS X app. Here's my solution.
First add an IBAction as you did above in your LayerDocument. Now go to Interface Builder. You'll see that in the connections panel to First Responder in your WindowController, IB has now added a Sent Action of addLayer. Connect your toolBarItem to this. (If you look at First Responder connections for any other controller, it will have a Received Action of addLayer. I couldn't do anything with this. Whatever.)
Back to windowDidLoad. Add the following two lines.
// This is the top view that is shown by the window
NSView *contentView = self.window.contentView;
// This forces the responder chain to start in the content view
// instead of simply going up to the chain to the AppDelegate.
[self.window makeFirstResponder: contentView];
That should do it. Now when you click on the toolbarItem it will go directly to your action.
I've been struggling with this question myself.
I think the 'correct' answer is to lean on the responder chain. For example, to connect a tool bar item action, you can select the root window controller's first responder. And then show the attributes inspector. In the attributes inspector, add your custom action (see photo).
Then connect your toolbar item to that action. (Control drag from your Toolbar item to the first responder and select the action you just added.)
Finally, you can then go to the ViewController (+ 10.10) or other object, so long as its in the responder chain, where you want to receive this event and add the handler.
Alternatively, instead of defining the action in the attributes inspector. You can simply write your IBAction in your ViewController. Then, go to the toolbar item, and control drag to the window controller's first responder -- and select the IBAction you just added. The event will then travel thru the responder chain until received by the view controller.
I think this is the correct way to do this without introducing any additional coupling between your controllers and/or manually forwarding the call.
The only challenge I've run into -- being new to Mac dev myself -- is sometimes the Toolbar item disabled itself after receiving the first event. So, while I think this is the correct approach, there are still some issues I've run into myself.
But I am able to receive the event in another location without any additional coupling or gymnastics.
As i'm a very lazy person i came up with the following solution based on Pierre Bernard
's version
#include <objc/runtime.h>
//-----------------------------------------------------------------------------------------------------------
IMP classSwizzleMethod(Class cls, Method method, IMP newImp)
{
auto methodReplacer = class_replaceMethod;
auto methodSetter = method_setImplementation;
IMP originalImpl = methodReplacer(cls, method_getName(method), newImp, method_getTypeEncoding(method));
if (originalImpl == nil)
originalImpl = methodSetter(method, newImp);
return originalImpl;
}
// ----------------------------------------------------------------------------
#interface NSResponder (Utils)
#end
//------------------------------------------------------------------------------
#implementation NSResponder (Utils)
//------------------------------------------------------------------------------
static IMP originalSupplementalTargetForActionSender;
//------------------------------------------------------------------------------
static id newSupplementalTargetForActionSenderImp(id self, SEL _cmd, SEL action, id sender)
{
assert([NSStringFromSelector(_cmd) isEqualToString:#"supplementalTargetForAction:sender:"]);
if ([self isKindOfClass:[NSWindowController class]] || [self isKindOfClass:[NSViewController class]]) {
id target = ((id(*)(id, SEL, SEL, id)) originalSupplementalTargetForActionSender)(self, _cmd, action, sender);
if (target != nil)
return target;
id childViewControllers = nil;
if ([self isKindOfClass:[NSWindowController class]])
childViewControllers = [[(NSWindowController*) self contentViewController] childViewControllers];
if ([self isKindOfClass:[NSViewController class]])
childViewControllers = [(NSViewController*) self childViewControllers];
for (NSViewController *childViewController in childViewControllers) {
target = [NSApp targetForAction:action to:childViewController from:sender];
if (NO == [target respondsToSelector:action])
target = [target supplementalTargetForAction:action sender:sender];
if ([target respondsToSelector:action])
return target;
}
}
return nil;
}
// ----------------------------------------------------------------------------
+ (void) load
{
Method m = nil;
m = class_getInstanceMethod([NSResponder class], NSSelectorFromString(#"supplementalTargetForAction:sender:"));
originalSupplementalTargetForActionSender = classSwizzleMethod([self class], m, (IMP)newSupplementalTargetForActionSenderImp);
}
// ----------------------------------------------------------------------------
#end
//------------------------------------------------------------------------------
This way you do not have to add the forwarder code to the window controller and all the viewcontrollers (although subclassing would make that a bit easier), the magic happens automatically if you have a viewcontroller for the window contentview.
Swizzling always a bit dangerous so it is far not a perfect solution, but I've tried it with a very complex view/viewcontroller hierarchy that using container views, worked fine.

Force landscape application to call supportedInterfaceOrientations (Again)

I Currently have a nearly landscape only iPad application on the app store and have been having some issues with the new iOS 6 way on handling rotation locking.
It is a UINavigationController based application and since iOS handles most the responsibility to the rootViewController of the UIWindow I have to manually ask each UIViewController what rotation it wants.
As I have a very large amount of UIViewControllers manually adding code to each Controller to do this would have taken me ages, So I made an extension of both the UINavigationController and UIViewController to override these calls and there I could manually set what views I want to block Portrait to and what ones to allow it to.
UINavigationController-Extension.m:
//
// UINavigationController-Extension.m
// DrivingInstructor
//
// Created by Liam Nichols on 06/12/2012.
// Copyright (c) 2012 Liam Nichols. All rights reserved.
//
#import "UINavigationController-Extension.h"
#implementation UINavigationController (Extension)
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return [self.topViewController shouldAutorotateToInterfaceOrientation:interfaceOrientation];
}
-(NSUInteger)supportedInterfaceOrientations
{
return self.topViewController.supportedInterfaceOrientations;
}
-(BOOL)shouldAutorotate
{
return YES;
}
#end
#implementation UIViewController (Extension)
-(BOOL)shouldAutorotate
{
return NO;
}
-(NSUInteger)supportedInterfaceOrientations
{
if ([[self portraitClasses] containsObject:NSStringFromClass([self class])])
{
return UIInterfaceOrientationMaskAll;
}
return UIInterfaceOrientationMaskLandscape;
}
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
if ([[self portraitClasses] containsObject:NSStringFromClass([self class])])
{
return YES;
}
return (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft || toInterfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
-(NSArray*)portraitClasses
{
static NSArray *classes;
if (classes == nil)
{
classes = #[ #"MockTestController", #"PLUILibraryViewController", #"PhotoViewController" ];
}
return classes;
}
#end
At fist I thought this had fixed the issue (I also kept the app locked to landscape in the info.plist so that it would launch to lanscape and then in the app delegate I called application:supportedInterfaceOrientationsForWindow: and returned all orientations so that my select views could access portrait if needed.
So this seemed to have worked and all view controllers where locked to lanscape accept the 3 I specified in my extension class.. I was monitoring the extension and whenever I pushed to the new controller it checked for the orientations and locked the app to the specified orientation.
The one issue I found however and can't seem to fix is that when i for example am in portrait on my allowed view controller and try to pop back to the previous view controller what is locked to landscape, supportedInterfaceOrientations is never called again and the view that should be locked to landscape isn't (this causes issues).
As per apples documents, this is how it should work as the responsibility of handling rotation is passed to the rootViewController and as the user isn't rotating their device and the rootViewController isn't changing there is no need to request supportedInterfaceOrientations..
My question is, is there a way to get the application to force call supportedInterfaceOrientations or should I be doing this differently?
Thanks for reading, and If I can find a solution to this last bug then this code might be a good reference to people who are also in the same situation.
-----Edit-----
Was doing some further investigation and found that just before the viewWillAppear: function, supportedInterfaceOrientations is actually in fact called on the controller I am attempting to pop back to and does return the correct mask UIInterfaceOrientationMaskLandscape to try and make it automatically rotate back from portrait however it doesn't seem to listen to this response and still leaves the UIViewController in portrait...
So this means that I do not need to call the supportedInterfaceOrientations again but instead make the device rotate back round to landscape!
According to the documentation you can call:
+ (void)attemptRotationToDeviceOrientation
which if I understand the documentation correctly then would query rotation to the different view controllers again.

How To Correctly Segue To An Embedded Tab Bar and Navigation Controller Using Storyboards?

I've got an app where the user selects their country from a picker wheel. An alert comes up and asks them to confirm the change. If they confirm, it takes them to a different view where they can then select from a list of categories to display information...
The list of categories is embedded in a Navigation Controller to facilitate moving from the detailed view "Back" to the category select view.
The entire app is embedded in a Tab Bar Controller.
It works fine (after selecting their country they are taken to the Select Category screen) except that now the Select Categories has lost its connection to the Tab Bar Controller and there is no way to get back to other parts of the app.
Here's my alertView code:
- (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0) {
NSLog(#"ok");
//I tried the following but it doesn't do anything
//SelectCategory *switchtocategory = [[SelectCategory alloc] init];
//[self.navigationController pushViewController:switchtocategory animated:YES];
//the following works but loses the tab/navigation bars
[self performSegueWithIdentifier: #"GoToCategory" sender: self];
} else {
NSLog(#"cancel");
}
}
Finding the answer was really about understanding the role of the Tab Bar Controller, how it defaults as the root view controller and then how to work with it to access the various view controllers, instead of trying to segue. Reading the Apple documentation helped with this but the code turned out to be very easy:
- (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 0) {
NSLog(#"ok");
//the following transitions to tab #3 when the alertView is touched/clicked/dismissed
[self.tabBarController setSelectedIndex:2];
} else {
NSLog(#"cancel");
}
}

iOS: popViewController unexpected behavior

I've been searching the internet for a solution. There's nothing I could find.
So:
I'm using a UINavigationController. I am pushing two UIViewControllers onto it. In the second pushed ViewController i am executing this code:
- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFailWithError:(NSError *)error {
NSLog([error localizedDescription]);
[self.navigationController popViewControllerAnimated:YES]; }
The expected thing to happen would be that the last pushed ViewController disappears. In this app I am doing this on few places and it works fine everywhere expect in this very ViewController.
What happens is that only the back button goes off screen (animated) but everything else stays on screen. In the Console Output two things are printed out when this line executes:
2011-03-14 16:32:44.580
TheAppXY[18518:207] nested pop
animation can result in corrupted
navigation bar
2011-03-14 16:32:53.507
TheAppXY[18518:207] Finishing up a
navigation transition in an unexpected
state. Navigation Bar subview tree
might get corrupted.
Two error messages I couldn't find ANY information on.
I'm using XCode 4 and iOS SDK 4.3. Maybe anyone can help me with this problem.
I came across a similar situation in my code and the message said:
nested push animation can result in corrupted navigation bar
Finishing up a navigation transition in an unexpected state. Navigation Bar subview tree >might get corrupted.
My finding to this issue was that I was pushing 2 view controllers one after the other in quick succession and both were animated.
In your case it seems that you might be popping multiple view controllers with animation one after the other.
Hence, while one view is undergoing animation you should not start animation on another view.
I also found that if I disabled animation on one view, the error message disappeared.
In my case it was a problem with the flow logic as I did not intend to push 2 view controllers one after the other. One was being pushed within the switch case logic and another after its end.
Hope this helps someone.
You can get this anytime that you try to pop before viewDidAppear. If you set a flag, then just check that flag in viewDidAppear, you wont have a problem.
I have created a drop-in replacement for UINavigationController that will queue animations for you and avoid this problem entirely.
Grab it from BufferedNavigationController
I had this problem, too, and here's what was causing mine:
In RootViewController, I am using several UISegmentedControl objects to determine which of many views to load next.
In that (sub/2nd) view, I was popping (by using the "Back" button) back to RootViewController.
In RootViewController, I was handling viewWillAppear to "reset" each of my UISegmentedControl objects to a selectedSegmentIndex of -1 (meaning no segment looks "pressed").
That "reset" triggered each of my UISegmentedControl objects to fire their associated (and separate) IBActions.
Since I wasn't handling for a "selection" of -1, I had multiple methods firing at the same time, all trying to push a different view.
My fix? I tightened up my if...then statements and bailed on executing any code in my UISegmentedControl IBActions when selectedSegmentIndex == -1.
I'm still not sure why I got "pop" animation errors and not "push" errors, but at least figured out my error and got it fixed!
Hope this helps someone else!
yeah, unfortunately apple did not synchronize UINavigationController's animations. Andrew's solution is excellent, but if you don't want to cover its whole functionality, there is a simpler solution, override these two methods :
// navigation end event
- ( void ) navigationController : ( UINavigationController* ) pNavigationController
didShowViewController : ( UIViewController* ) pController
animated : ( BOOL ) pAnimated
{
if ( [ waitingList count ] > 0 ) [ waitingList removeObjectAtIndex : 0 ];
if ( [ waitingList count ] > 0 ) [ super pushViewController : [ waitingList objectAtIndex : 0 ] animated : YES ];
}
- ( void ) pushViewController : ( UIViewController* ) pController
animated : ( BOOL ) pAnimated
{
[ waitingList addObject : pController ];
if ( [ waitingList count ] == 1 ) [ super pushViewController : [ waitingList objectAtIndex : 0 ] animated : YES ];
}
and create an NSMutableArray instance variable called waitingList, and you are done.
This problem happen with me when i use storyboards. I've made a mistake:
I have a UIButton with an action to performSegueWithIdentifier. So i link the push segue with Button with the other ViewController so occur this problem.
To solve:
Link the button action in UIButton and link the push segue between two ViewControllers.
Combining MilGra and Andrew's answers gave me something that works reliably and is a simpler drop-in UINavigationController replacement.
This improves on MilGra's answer to make it work with pushes and pops, but is simpler than Andrew's BufferedNavigationController. (Using BufferedNavigationController I was occasionally getting transitions that would never complete and would only show a black screen.)
This whole thing seems not to be necessary on iOS8, but was still needed for me on iOS7.
#implementation UINavigationControllerWithQueue {
NSMutableArray *waitingList;
}
-(void) viewDidLoad {
[super viewDidLoad];
self.delegate = self; // NOTE: delegate must be self!
waitingList = [[NSMutableArray alloc] init];
}
# pragma mark - Overrides
-(void) pushViewController: (UIViewController*) controller
animated: (BOOL) animated {
[self queueTransition:^{ [super pushViewController:controller animated:animated]; }];
}
- (UIViewController *)popViewControllerAnimated:(BOOL)animated {
UIViewController *result = [self.viewControllers lastObject];
[self queueTransition:^{ [super popViewControllerAnimated:animated]; }];
return result;
}
- (NSArray*)popToRootViewControllerAnimated:(BOOL)animated {
NSArray* results = [self.viewControllers copy];
[self queueTransition:^{ [super popToRootViewControllerAnimated:animated]; }];
return results;
}
# pragma mark - UINavigationControllerDelegate
-(void) navigationController: (UINavigationController*) navigationController
didShowViewController: (UIViewController*) controller
animated: (BOOL) animated {
[self dequeTransition];
}
# pragma mark - Private Methods
-(void) queueTransition:(void (^)()) transition {
[waitingList addObject:transition];
if (waitingList.count == 1) {
transition();
}
}
-(void) dequeTransition {
if (waitingList.count > 0) {
[waitingList removeObjectAtIndex:0];
}
if (waitingList.count > 0) {
void (^transition)(void) = [waitingList objectAtIndex:0];
if (transition) {
transition();
}
}
}
#end

Resources