iOS - strangeness in the navigationController - iphone

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)];

Related

Dismissing 3 layers of modal view

In my application, I have three layers of modal view controllers.
1) So my rootViewController is a tabbar.
2) On applicationDidFinishLaunching I am presenting a viewController, say viewController A modally above tabbar.
3) On click of a button in 'viewController A', I present another viewController B modally.
4) And a button action on viewController B presents navigationController modally with its rootViewController as viewController C.
5) Finally from viewController C, I want to go back to viewController A.
I tried using
[[[self parentViewController] parentViewController]dismissModalViewControllerAnimated:YES];
in viewController C, but it reverts me back to viewController B instead of viewController A.
How can I revert back to viewController A.
Any help would be appreciated.
push all the 'modal' views on a navigationControl with a transitionStyle that looks like the modalTransitionStyle..dont reinvent stuff
present all in one modal navigationController Id say :)
You've got a complex VC stack. You could as one poster suggested implement a custom dismissView method, but that would be fragile: if you reuse this view, or move it in your app, it will cease functioning, because it relies too much on specific knowledge of how other VCs have configured their state.
You could configure a delegation chain. This would be the standard way to manipulate views: the presenting VC is also responsible for removing anything it presents.
To do so, build a protocol implemented by B, and initialize C with a reference to B. Similarly, initialize B with a reference to A (with potentially the same protocol, depending on any other communication that needs to be passed between them.)
Then when the button is clicked on C, it calls B's delegate method. B unwinds C as appropriate, and calls A's delegate method. A unwinds B as appropriate.
This has the advantage of keeping VC knowledge encapsulated: A knows how it presented B, so it knows how to unpresent it, and B knows how it presented C, and knows how to un-present it. In no case does one VC need to make assumptions about how it was presented by another.
Implement the view dismissing method like:
- (IBAction)dismissView
{
[self dismissModalViewControllerAnimated:NO]; // dismiss c
[[self parentViewController] dismissModalViewControllerAnimated:NO]; //dismiss b
}
[self parentViewController] will return the parent view of viewControllerC, that's viewControllerB. So it'll dismiss that view too.

iPhone - a question about navigationControllers and viewController

I have a project based on Xcode's NavigationController template. This template has a navigationController and a RootViewController.
From inside this RootViewController I push a view and this view pushes a third view. Something like:
NavigationController >> RootViewController >> ViewController 1 >> ViewController 2
Now, from ViewController2 I want to access the navigationController and the navigationController.toolbar.
I know that every viewController has the navigationController property but my question do I have to do something when I push a new viewController so this variable (on the view that is being pushed) will have a valid reference to the correct ViewController or all pushed views will always have a valid reference to the navigationController?
The reason for my question is that I am trying to access the navigationController.toolbar, to make it invisible, and I am having no result.
thanks.
You might want to try -[UINavigationController setToolbarHidden:animated:] to hide the toolbar instead:
[self.navigationController setToolbarHidden:YES animated:YES];
This has always worked for me no matter how deep in the navigation stack my view controller was.
In the entire navigation stack of one UINavigationController object, every view controller's navigationController property has the same value.
The navController is like a box that contains the viewControllers within, with the last one to be pushed shown to the user until it is popped off, when the one below it will come to life again.
This means you can rely on the navController instance always being available from within a controller that was pushed by the navController.

iphone - Nav-bar app crashing

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

iPhone: How to Trigger the Loading of a View Using a UI Element in a Previous View

I've been reading the Head First iPhone Development book and I understand how to get to a new view from a table but how exactly would I be able to get to a new view or view controller, by just simply pressing a button? Is that even possible?
I mean there are some apps where you click a button, not a table cell and it loads a new view. How exactly is that done? If someone could help out a newbie it would be greatly appreciated!
I think what you're looking for is a modal vew controller. THis presents a modal view like you described on top of everything else. If rootViewController is the view controller that is displaying your current view, and myNewViewController the view controller you want to display modally:
[rootViewController presentModalViewController:myNewViewController animated:YES];
There's plenty of examples of this kind of thing on the net, just search for presentModalViewController
Like bpapa said in the comments, it's hard to be specific without code. However, generally what you want to do is:
Build a navigation controller that contains one original view.
Create a button in your original view using the Interface Builder.
Build a callback method (usually defined with IBAction) that is run when the button is pushed.
In that callback method, create a new view and push it onto the navigation controller the same way you would using a table view cell.
Alternately, if you only want one level of hierarchy, you could use a modal view controller; instead of pushing onto the navigation controller in the last step, just present the modal view controller.
The general answer is that you have an object that manages which view controller loads when.
The most commonly used is the UINavigationController. It is a UIViewController that instead of controlling views, controls other view controllers. It works like a simple stack. You push views you want to display onto the nav's controller stack and when you want them to disappear you pop them off.
A common (though sloppy) way of using a nav is to make it a property of your app delegate. Then anywhere in your app you can references it by:
UINavigationController *nav=[[[UIApplication sharedApplication] delegate] navigationController];
The view controller for the first the user sees is held in the nav's topViewController property. If you want to load a view based on a user action in the topViewController.view, you would have something like this:
- (IBAction) loadNextView:(id) sender{ // Action called by a a UI event such as a button press.
UINavigationController *nav=[[[UIApplication sharedApplication] delegate] navigationController];
UIViewController *nextViewController=...// load from nib, connect with IBOutlet, create programmatically
[nav pushViewController:nextView animated:YES];
}
The first view disappears to be replaced by the next one. To return to the first view, you have a method in the next view controller like so:
- (IBAction) unloadSelf:(id) sender{ // Action called by a a UI event such as a button press.
UINavigationController *nav=[[[UIApplication sharedApplication] delegate] navigationController];
[nav popViewControllerAnimated:YES];
}
... and the nav returns you automatically to the previous view regardless of what that view was.
When you first start out, especially if you use Interface Builder, the structure of the app is largely hidden. Behind the scenes all view controllers and their views exist in a hierarchy of some kind that leads back up to the app delegate. You should train yourself to think in hierarchal terms even if it is not immediately obvious how that hierarchy is constructed.

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.