UINavigationController & "Pushing a navigation controller is not supported" Exception? - ios

I was trying to redo an example of How to create UINavigationController based application from Beginning iPhone Development by Appress.
I'm getting the following exception:
Exception: Pushing a navigation controller is not supported
Exception: [NSException]:Pushing a navigation controller is not supported
ex.name:'NSInvalidArgumentException'
ex.reason:'Pushing a navigation controller is not supported'
It happens when user try to push a view that is already in the stack, Which is not true in my case.
My_3AppDelegate.h
IBOutlet UINavigationController * navController;
#property (nonatomic, retain) UINavigationController * navController;
My_3AppDelegate.m
[window addSubview: navController.view];
MainWindow.xib adds UINavigationController to the window an connected to the outlet.
The only difference in my code is RootViewController is not a subclass of UITableViewController. It's just UIViewController with 2 UIbuttons.
FirstViewController *fv = [[FirstViewController alloc] initWithNibName:#"FirstViewController" bundle:nil];
fv.navigationItem.title=#"First View Controller";
[self.navigationController pushViewController:fv animated:NO];
[fv release];
That error occurs with the initial run of the application, which make sure that, It's not like that, the view was already added to the stack and I'm trying to readied.
Its a very simple tutorial application that I'm stuck in and I'm not sure why?
Any idea?

I've solved the same problem by changing super class from UINavigationCotroller to UIViewController.

Related

UINavigationController embedded in container view from Storyboard won't push UIViewController

In my storyboard for a container class, I have created a full-screen Container View with an embed segue that's attached to a UINavigationController. I'm trying to test this by pushing a viewController programmatically like below:
UIViewController* test = [[UIViewController alloc] init];
test.view.backgroundColor = [UIColor redColor];
UINavigationController* navC = [[RootController mainStoryBoard] instantiateViewControllerWithIdentifier:#"containerNav"];
[navC pushViewController:test animated:NO];
navC is successfully initialized as the navigation controller, but the pushViewController call seems to do nothing. I still just see an empty navigation controller on the screen (default navigation bar with black view). I also tried a similar test with the setViewControllers method, which also failed. Are navigation controllers not meant to be embedded into container views?
UINavigationController needs a UIViewController at the bottom of its stack from when it is first created, (and it can't 'pop' that one). In other words it can't begin with an empty stack, you should be adding/embedding one viewController inside it in the xib/storyboard, then I expect it'll work with what you're doing here
I think you may need to just set the viewControllers property on the Nav Controller, like this:
[navC setViewControllers(#[test] animated: NO]

Present ViewController on UISplitViewNavigator's MasterViewController

I've created a new XCode project using the SplitViewNavigator template. One of the MasterViewController's navigationItems should present a configuration ViewController (fullScreen on iPhone, popup on iPad).
This config controller has been created in a separate storyboard (Filter.storyboard).
In this storyboard I dragged a ViewController on the stage and embedded it in a Navigation Controller (Editor -> Embed In -> Navigation Controller) because the config itself consists of different screens the user can go through.
The NavigationController has been given a StoryBoard ID "FilterNavController".
I've done this several times in other applications, so this does work. Unfortunately, I can't get it working with the SplitViewNavigator template.
Here is how I try to open the filter controller once the button has been tapped, nothing special about it;
UIStoryboard *filterBoard = [UIStoryboard storyboardWithName:#"Filter" bundle:nil];
UINavigationController *filterNavController = [filterBoard instantiateViewControllerWithIdentifier:#"FilterNavController"];
UIViewController *vc = [filterNavController.viewControllers objectAtIndex:0];
[self.navigationController presentViewController:vc animated:YES completion:nil];
self is the MasterViewController.
From my uneducated point of view, I don't see any reason why this wouldn't work. As I said, it does in other (non SplitViewNavigator template) applications.
The error message I'm getting is the following:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Application tried to present modally an active controller <UINavigationController: 0x7f9bab61a700>.'
No idea what the heck is going on here but it already cost me half a day.
Interestingly, when I just create a UIViewController on the Filter.storyboard and set its StoryBoardID, the ViewController will get presented. However, I need it to be embedded in a UINavigationController.
Any help would be highly appreciated!
For the sakes of completeness, the following method works nicely for instantiating ViewControllers from a Storyboard.
Instead of creating a UINavigationController on the Storyboard, just create the ViewController(s) and embed them in a UINavigationController on code.
UIStoryboard *myBoard = [UIStoryboard storyboardWithName:#"MyStoryboard" bundle:nil];
MyViewController *menuController = [myBoard instantiateViewControllerWithIdentifier:#"MyViewController"];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:myController];
[self presentViewController:navController animated:YES completion:nil];

iOS change view controller from the app delegate?

Above is the storyboard for my chat app.
What you'r not seeing to the left before the Navigation Controller is a simple login view. The Storyboard Segue identifier to the Navigation Controller is mainViewC.
What i want to do is to take the user to the Conv View Controller when a push notification is pressed.
This is what i've got so far:
// AppDelegate.h
#property (strong, nonatomic) ConvViewController *convViewController;
// AppDelegate.m
self.window.rootViewController = self.convViewController;
This takes me to the correct view but the view is black. Im guessing this has something to do with the Navigiation Controller not being loaded correctly..
Any ideas?
What you'll need to do is access the view controller from the story board. First go to the VC you wish to bring users to and give it a Storyboard ID. Then in your app delegate you would write.
self.window.rootViewController = [[UIStoryboard storyboardWithName:#"Main" bundle:[NSBundle mainBundle]] instantiateViewControllerWithIdentifier:#"identifier"];

UINavigation pushing a new root controller

I am trying to push a new root controller to a navigation stack, but using a side reveal menu.
My app delegate has the following:
welcomeViewController = [[MyWelcomeViewController alloc] initWithNibName:#"MyWelcomeViewController" bundle:nil];
navController = [[UINavigationController alloc] initWithRootViewController:welcomeViewController];
navController.navigationBarHidden = YES;
// Then we setup the reveal side view controller with the root view controller as the navigation controller
self.revealSideViewController = [[PPRevealSideViewController alloc] initWithRootViewController:navController];
[self.revealSideViewController setDirectionsToShowBounce:PPRevealSideDirectionNone];
[self.revealSideViewController setPanInteractionsWhenClosed:PPRevealSideInteractionContentView | PPRevealSideInteractionNavigationBar];
// Then we make the window root view controller the reveal side view controller
self.window.rootViewController = self.revealSideViewController;
Once the welcome view controller is displayed, the user logs in. Once logged in the following process runs again from the App Delegate.
self.navController.navigationBarHidden = NO;
[self.navController setTitle:#"Home"];
[self.navController pushViewController:homeViewController animated:NO];
I then have a side view controller setup which is a table view with custom cells setup.
When a row is selected I need to push a new root controller onto the navigation controller. I try this by using the following in the table view for the cell selected.
MyAccountViewController *accountViewController = [[MyAccountViewController alloc] init];
[self.navigationController setViewControllers:[NSArray arrayWithObject:accountViewController] animated:NO];
Unfortunately this does not do anything. If I add the code to the App Delegate and then call the method from the table view controller then it works, however not from the .m file for the table view itself. Adding a log I can see the above is run, just does not do anything.
I am unsure if I need to do anything different on the above. For example, completely pop the views currently shown, then create the navigation controller and PPRevealSideViewController all over again. If I am supposed to, I am unsure how to pop all the current views to then push the new to the window, not from the AppDelegate.
The reason I do not want this in the App Delegate is because it is the incorrect way to approach this, and I would then need a separate method for each new root controller I would like to push from the menu, so the App Delegate would become very large.
Check UINavigationController.h:
#interface UIViewController (UINavigationControllerItem)
#property(nonatomic,readonly,retain) UINavigationController *navigationController; // If this view controller has been pushed onto a navigation controller, return it.
It means when you do myViewController.navigationController you will either get nil if myViewController is not pushed to any navController or the navController reference myViewController is pushed into.
As I understand your tableViewController is not pushed into the navController stack, that means you can't get the navController with tableViewController.navigationController. Instead you'll need to use anyViewControllerInTheStack.navigationController or if the navController is the rootViewController of your keyWindow, by
((UINavigationController*)[[UIApplication sharedApplication] keyWindow].rootViewController)
Add something like this to your AppDelegate.h:
#define XAppDelegate ((AppDelegate *)[[UIApplication sharedApplication] delegate])
Now you can access any iVar of AppDelegate from any .m file in your project.
MyAccountViewController *accountViewController = [[MyAccountViewController alloc] init];
[XAppDelegate.navController pushViewController:accountViewController animated:NO];
Make sure you add the correct imports.
One more thing: It's good to pop the login window from your navcontroller once you are done Logging in.
Hope this helps.

pushViewController pushes but no view change

When I try to push a UIViewController subclass (MissionViewController) onto a UINavigationController from within my root view controller, the viewDidLoad method is only called if I reference the underlying view after initializing the view controller. However, even with the method called, the screen is not updated.
Both the view controller and the navigation controller are not nil. The file owner in MissionView.xib is set to MissionViewController. The view property of the file owner points to the nib view. I've verified that the topViewController property of the navigation controller points to the MissionViewController object.
If I change MissionViewController to be the root view controller, the view loads fine. Saw several similar posts but still having problems.
rootViewController.h
#interface TreeGraphController : UIViewController
{
MissionViewController *missionViewCtrlr;
}
#property(nonatomic, retain) MissionViewController *missionViewCtrlr;
rootViewController.m
#import "MissionViewController.h"
...
if (!missionViewCtrlr)
{
MissionViewController *ctrlr = [[MissionViewController alloc] initWithNibName:#"MissionView" bundle:nil];
ctrlr.view.hidden = NO;
self.missionViewCtrlr = ctrlr;
[ctrlr release];
}
myAppDelegate *del = [[UIApplication sharedApplication] delegate];
[del.navigationController pushViewController:missionViewCtrlr animated:NO];
What about using
[self.navigationController pushViewController:missionViewCtrlr];
in the rootViewController? I assume rootViewController has been pushed to a UINavigationController and that the navigation controller's view was added as a subview of self.window in the app delegate?
Btw, you may simplify part of your code by just saying
if(!missionViewCtrlr)
self.missionViewCtrlr = [[MisionViewController alloc] init...];

Resources