iphone - Nav-bar app crashing - iphone

I have a tabbar controller app with two tabs. One of my tabs uses a navigation controller.
The navigation controller that I made for this resides in View A. View A acts solely as a controller and automatically pushes View B which in turn pushes view C which pushes View D.
I want the next view to be View B, so I used
NSArray *viewControllers = [[self navigationController] viewControllers];
int i=0;
while (! [[[viewControllers objectAtIndex:i] nibName]
isEqualToString:#"ViewBController"]
&& i < [viewControllers count])
i++;
to get the view I want (in some cases the order of the views may change so I don't want to hardcode it)
and then
self.navigationController popToViewController:[viewControllers objectAtIndex:i] animated:NO];
to get back to view B
My issue is that the app crashes at this point. Well technically it crashes after it deallocs View C (I put nslogs there to figure that out).
I have no idea what my issue can be? Can anyone provide insight?
EDIT: I also tried making a new view controller, View E, and pushing that and it still crashes

I finally figured out my problem, it turned out not to be a navigation issue.
Before switching views I had an alert that I set to autorelease, and then I also released it.
I figured this out by using NSZombie, which is awesome.
For anyone who needs the reference check this out:
http://cocoadev.com/index.pl?NSZombieEnabled

First, a clarification... When you say that your nav controller resides "in View A" what exactly do you mean? Do you mean it is the View Controller contained on the first tab?
So far it looks like you might have a fundamental misunderstanding of how to use a navigation controller. They aren't supposed to be loaded so that you can flipped through to whichever one you want. Each view controller in the navigation controller should be a new screen that your user has chosen to navigate to. It sounds like you are trying to populate the nav controller with a bunch of view controllers and then push or pop to one of them in the middle, but that's not really how it works.
Here is a video explaining how to use a UINavigationController, perhaps it will help. http://vimeo.com/2371881

Related

iOS - strangeness in the navigationController

I have createa an app that is based on "Single View Application" Xcode template. It has a navigation controller and a rootViewController.
When I am on the rootViewController and I do
[self presentModalViewController:nextModalViewController animated:YES];
the new view controller is animated in.
My problem is this. I have presented a lot of viewControllers in sequence, that is
A > B > C > D
or in other words, I have presented B from A using presentModalViewController, C from B and so one. Yes, I have to use presentModalViewController because I have a special animation going on to transition between viewControllers and I cannot use [self.navigationController push...
My question is: what happens when I use presentModalViewController regarding to the navigation stack? Is the controller being presented pushed to some stack? is there a way to obtain references to all navigationControllers that were presented at a given time? something like that navigation stack? I mean, suppose I am on D and I want to get a list of all controllers presented before D.
I know I can create properties and pass that along. I am just wondering if theres something already built on iOS that does that.
thanks.
In iOS 5 and later, UIViewController has a presentingViewController property that returns the view controller that presents the receiver. In iOS 4 and earlier, use the parentViewController property of the presented view controller to access its presenting view controller. So you can access, for example, the C view controller from D by accessing these properties appropriately. See the docs for further information.
If you want to access all the view controllers as in a chain, you can do this:
UIViewController *node = self;
while (node != nil) {
// do something with the view controller, then skip to its parent
node = node.presentingViewController;
// or node = node.parentViewController; in iOS 4 or older
}
I'd subsequently check the size of the viewControllers property from your UINavigationController after every modal presentation, and check if it grows or not.
UIViewController *theControllerYouWant = [self.navigationController.viewControllers objectAtIndex:(theIndexOfYourViewController)];

Navigation Bar Back Button Pop View Controller

When hitting the Back button on a navigation controller, does the view get popped off the stack? If so, how can I test that or make sure that it does it correctly (in other words, created a proper navigation controller)?
I need to see if the view is actually getting popped. Is there anything I can NSLog that shows me the stack or something?
Thanks,
Yes, the view is popped from the stack. You can check the size of the stack (number of views) to confirm this.
The viewController is getting popped from the stack yes. You can also NSLog(#"%#", self.navigationController.viewControllers); in - (void)viewWillAppear and - (void)viewDidAppear methods of the parent viewController to see the differences if you don't trust that Apple engineers did a good job with it.
NSLog(#"%#", self.navigationController.viewControllers); would give the viewcontrollers array in navigation stack.you can nslog them before the view disappears and after the other view appears

Keep new view in a tab when switching to another tab

This is the situation:
I have a tab bar with 2 tabs. Tab01 and Tab02.
In Tab01 I have a button which pushes repVC:
repVC.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:repVC animated:YES];
[(UIViewController *)[tabController.viewControllers objectAtIndex:0] setView:repVC.view];
[repVC release];
Inside repVC I have another button which pushes an MFMailComposerViewController:
MFMailComposeViewController *mail = [[MFMailComposeViewController alloc] init];
[self presentModalViewController:mail animated:YES];
[mail release];
The problem is: when mailView is shown(in Tab01) and I click Tab02, then back to Tab01, the mailView is hidden and even if I click the email button again, the view won't be presented.
So what I have is: Tab01.view -> repVC.view -> mail.view
For repVC, I use this line when I push the view so that even if I go switch tabs, that view will still be activated:
[(UIViewController *)[tabController.viewControllers objectAtIndex:0] setView:repVC.view];
But I can't do the same for mail because tabController is declared in another class which I cannot import. So I can't access the tabController and set the view for Tab01.
Hope the edit helped the understanding.
Hmm,
I still would suggest to use a Navigationcontroller. Would make things way easier, is conform to apple guidelines and suggestions and is pretty fast implemented. (Just create a Navigationcontroller, put the View of Tab1 as main view and hand it over to the TabbarController. Then for the mailView use [self.navigationController pushViewController:mail animated:YES]; Then the navcontroller "saves" the present view for you when u switch tabs)
But if for some Reason you have to use a modalViewcontroller you could either just deactivate the tabbar while the ModalView is shown or try to implement a switch or a simple if...else case in your ViewWillAppear where u check what screen to load.
Then Clean out the Window and load the right screen.
Hope you get the idea of what I mean, sometimes my way of writing seems to confuse people. ^^
A little more information would be great.
How did u set up your TabbarController?
How do u push the new view? Within a UINavigationController? If not, then do it with a navController, he should save the actual state of view and your problem should be solved.
If u already use a navController please post your ViewDidLoad and ViewWillAppear of the Viewcontroller of Tab 1
As #Amandir points out you could probably solve your problems by using a UINavigationController. I get a feeling that you are trying to abuse the modal view controller concept a bit and that's why it doesn't work as you expect. When you use presentModalViewController:animated: the intention should be that you are displaying a view that is modal, i.e. the user must interact and dismiss the modal view before she can continue.
What the paragraph above means that when you present a modal view controller it shouldn't be possible to use the tab bar. Since you are using the word push I'm guessing that you would like change the view of Tab01 while still being able to use the functionality of the tab bar. The problem is that there isn't any built-in method of pushing view controllers besides UINavigationController. persentModalViewController:animated: should only be used in case where you want a modal view, which on the iPhone means a full screen view.
The easiest way would probably be to use an UINavigationController and hide the navigation bar. Then you would get the functionality I think you are after. The other option is to manually add and remove sub views.
[self.view addSubview:repVC.view];
and
[repVC.view removeFromSuperview];
[self.view addSubview:mail.view];
You can use block animations if you want some fancy transitions.

UINavigationController not popping UINavigationBar items on iPad

I'm having a very strange problem with the UINavigationController.
I found a very similar question here:
UINavigationController not popping UINavigationBar items
but the solution there had to do with the fact that the guy had added a category to NSMutableArray, and I'm not doing anything like that.
In short, the problem is this: I have a navigation controller and I'm pushing a few view controllers on it. Then when the 'back' button is tapped the view controller is popped, but the corresponding navigation item isn't. If I tap back again, then the navigation item is popped.
Besides, it only happens when using the back button from the navigation controller's navigation bar. If I call popViewController explicitly (for example from a button press), it works as expected.
And this only happens on my iPad running OS 3.2, but not on my iPod Touch running OS 3.0 or on the simulator.
I've been trying to isolate the problem in a separate project from the rest of my app so I can experiment with it, but I can't get it to reproduce, though it occurs 100% of the times on specific views in my app.
I know that's not nearly enough information to get an specific answer, but I just wanted to know if anyone ever heard of a navigation controller not popping the navigation items as expected, just so I could have some clue as to where to investigate next.
Here's an example of the code I use to push a view controller, it's pretty straightforward, I'm not trying to do anything special with it:
// pushing a view controller from a button press (set up with interface builder)
- (IBAction) tappedExtras
{
ExtrasViewController *controller = [[ExtrasViewController alloc] initWithNibName:#"ExtrasViewController" bundle:nil];
[self.navigationController pushViewController:controller animated:YES];
[controller release];
}
note: in that example I'm using a custom view controller class called ExtrasViewController, but the problem happened with any kind of view controller I tried.
And here's a bit of code used to pop the view controller explicitly, also triggered by a button press set up with interface builder:
- (IBAction) cancelChanges
{
userCancelled = YES;
[self.navigationController popViewControllerAnimated:YES];
}
this works perfectly (popping the view controller explicitly), but on the exact same view controller if instead of tapping the button set up with interface builder you tap the back button on the navigation bar, the navigation item is not popped correctly.
I got the same issue with navigation that subsist after poping the third level pushed view controller.
The issue only appear in landscape on iPad. No issue on the iPhone (3.1.3 & 4.0). Of course, it's ok on the simulator.

iPhone SDK: How to display a view controller within another?

Fundamentally, what I want to do is within, for example, ViewControllerA display ViewControllerB and ViewControllerC. How would I do that?
Thanks in advance.
You don't display view controllers, you display views. Having said that, you can do something like this:
UIViewController *a = ...;
UIViewController *b = ...;
[a.view addSubview:b.view];
Now, having said that, you shouldn't do it. Tons of stuff does not behave properly, because there are tons of undocumented interactions between UIView, UIWindow, and UIViewController. There is nothing in the documentation that says it won't work, but random things stop behaving properly (viewWillAppear: on the interior view's VC doesn't get called, etc).
If you need this functionality, you should file a bug with Apple.
The default template for a navigation view controller should do what you want assuming you want two different screens (not two different sections on the same screen). Whenever you want to change the view from the current one to another, just tell the navigation controller to push it on the stack:
[self.navigationController pushViewController:viewBoards animated:YES];
The default navigation view controller gives you a root view controller with a navigation view controller in it. It also gives you one view controller called MainWindow. Just add as many copies of MainWindow as you need to get your functionality.