How to navigate from subview to other view controller? - objective-c

Assume that I am having one view controller called MainPage(This is rootViewController).
In that view controller , I am adding one sub view.
See Below :
FirstPage1=[[FirstPage alloc] initWithNibName:#"FirstPage" bundle:[NSBundle mainBundle]];
[self.view addSubview:FirstPage1.view];
In that subview , I need to navigate to next page.
so that i have used presentViewController like below code but its doen't worked well.
See Below Code:
[self.view.window.rootViewController presentViewController:AnotherViewController animated:YES completion:nil];
It works well on first time but if I called for next time , I got below error.
Error :
whose view is not in the window hierarchy!

Having separate view controllers being linked together is a good use for UINavigationController. Just make a UINavigationController and add its view to self.view on your example. Then, do [navController pushViewController: animated:] for each view as needed. Or pop the last view controller, then push the new one if you don't want old pages to be accessible. From how your project seems to be set up, that's the easiest way.

Related

Load view with the navigation controller?

I have an app where my main view is embedded in a navigation controller. From there, buttons push onto other view controllers. This all works fine. However, one of the view controllers it pushes to updates one of the root's values and presents it again. However this time, it only presents the ViewController without the navigation controller, and of course, pressing the button to go back will end in a crash. Hopefully this picture will help understand my issue. The pressing enter thing isn't really a big deal, I just call this function on return of the keyboard.
Code to go back to the main controller:
-(void)createNewMain:(NSString*)newAddress {
ViewController* newController = [self.storyboard instantiateViewControllerWithIdentifier:#"MainView"];
newController.labelText = newAddress;
newController.connected = self.connected;
[self presentViewController:newController animated:YES completion:nil];
}
The problem is simple, you're presenting the instantiated view controller modally.
Replace
[self presentViewController:newController animated:YES completion:nil];
with
[self.navigationController pushViewController:newController animated:yes];
Also, you can make a segue to do that from the storyboard. When the segue executes, it will create a new instance and will not use the previously created one.
Note: If you really don't need to create a new instance, consider using delegation to exchange information between objects.
You don't really want to "return" to a new instance of a root controller. What you need to do to properly return to the root controller is to pop all the other ones from the navigation controller's stack like this:
[self.navigationController popToRootViewControllerAnimated:YES];
Use Delegation to pass the expected/required message you want from your Pi Controller to your Root View Controller and set it up according to the message. You don't need to create a new instance of your Root View Controller from there. You can always go back to your root view controller from anywhere in the navigation stack by using
[[self navigationController] popToRootViewControllerAnimated:YES];

Perform Seque of initial view controller inside the App Delegate

ive got a navigation controller with a simple view as its rootsview. it has a button connected via a seque to a second view controller. The seque cause the second view controller to show up modal. If a condition isnt true i directly want to show up this second view controller after application launched.
I tried out a lot of code but it just wont work. Here is a screenshot of my scene :
Any Ideas how to do this?
I tried the following :
UIStoryboard *storybord = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
UINavigationController *vc = [storybord instantiateInitialViewController];
[[vc.viewControllers objectAtIndex:0] performSegueWithIdentifier:#"simple" sender:self];
but i got the following error message :
Attempt to present <UINavigationController: 0x71b2ab0> on <UINavigationController: 0x71b12c0> whose view is not in the window hierarchy!
I assume you're trying that sample code from app delegate? You need to make sure you don't try to perform the segue until after the first view is loaded. Coincidentally, if you wait until then, its much easier as all you need to do the performSegueWithIdentifier. Thus, in the viewDidLoad of the first view controller, e.g.:
if (bShouldAutomaticallyPerformSegueToSecondVC)
[self performSegueWithIdentifier:#"simple" sender:self];
Obviously, replace bShouldAutomaticallyPerformSegueToSecondVC with whatever logic is appropriate to determine when you automatically want to go to the second view controller.

Does presentModalViewController: add the view controller to the stack?

I have a main navigation controller with a root view controller. In the root view controller, on the push of a button I present second view controller like this:
SecondVC *secondVC = [[SecondVC alloc] initWithNibName:#"SecondVC" bundle:nil];
[self.navigationController presentModalViewController:secondVC animated:YES];
In the second view controller, on the push of an other button, I want to present a third view controller (this time from a Storyboard):
ThirdVC *thirdVC = [[UIStoryboard storyboardWithName:#"Settings" bundle:nil] instantiateInitialViewController];
[self.navigationController presentModalViewController:thirdVC animated:YES];
However this doesn't do anything. I debugged and it turned out, that self.navigationController is nil.
Shouldn't it be the main navigation controller? Or doesn't presentModalViewController: add the view controller to the stack? Do I always have to put a view controller in a navigation controller before presenting id modally?
The new view controller SecondVC is being presented modally, and it's not added to the view controller stack of the navigationController. You need to create a new UINavigationController, and put SecondVC inside the navController before presenting it modally.
You'll need to add something like:
UINavigationController *navControl = [[UINavigationController alloc] initWithRootViewController:secondVC];
[self addChildViewController:navController];
[self.navigationController presentModalViewController:secondVC animated:<#(BOOL)#>]
your view controller while being presented is not inside a navigation controller. And will not have access to the presenting controllers navigation controller.
Furthermore if you push or pop stack items on the navigation controller beneath the modal view controller you will likely not notice anything.
If you want to put the controller in the stack you can alternatively show the view controller yourself.
[self.view addSubView:myViewController.view]
myViewController.view.frame = self.view.bounds;
and to dismiss the view controller you would simply remove it from its superview.
the drawback here is that some of the did and will appear methods are not called on the view controller. Therefore you may want to call them yourself.
But the principal is much the same. And you can easily simulate the presenting animation with the animation system.
Give it a starting point below your form, then start your animation block and put the view.frame to superview.bounds also giving it an animation time. I find that 2 seconds is ok. sometimes less.
at this point the presented view is inside the controller which is on the stack. Now while you cant directly modify the navigation controller within the presented view controller you could set a delegate that tells the original your intentions and therefore the presenting view controller (the one on the navigation stack) can push or pop the view controllers as requested. And the presented view controller will be pushed along with it.
Another positive point is that you can do much like other apps do, and present a semi modal view. With a partially transparent background. this way you can show things happening behind the view even tho they dont directly manipulate it.

loading a UINavigation controller from a UIView

i am designing an app that has a login screen. it is a UIView with username/password and a button to submit. once the user authenticated successfully, i want to load a new xib file that holds a navigation controller and a navigation bar. below the bar i want to load a tableView and switch between other views as i move along with the programming of it.
what i did is create a new class that inherits from UINavigationController and assembled the xib file to include the navigation controller. i hooked it back up to file's owner and i'm loading the navigation controller modally like this:
myNavController* navVC = [[myNavController alloc] initWithNibName:#"navXibFile" bundle:nil];
[self presentModalViewController:navVC animated:YES];
[navVC release];
this works okay as the navigation controller shows up. however, it shows up with no title, even though i've set one up in IB. moreover, the tableView's delegates are hooked up via IB but i cannot even see empty lines. all i see is an empty navigation bar at the top and blank view (one piece) below it.
thank you for your help.
so i figured it out... first it's a design decision right? is the app being managed by a navigation controller? if so (which is my case), expect the main (first) view, that is a login page, all you need to do is to hide the navigation bar in your ViewdidLoad for the main view:
[self.navigationController setNavigationBarHidden:YES animated:YES];
once the user logs in and you push the next view like this:
MainTableViewController* mainTableVC = [[MainTableViewController alloc]
initWithNibName:#"MainTableViewController" bundle:nil];
[self.navigationController pushViewController:mainTableVC animated:YES];
[mainTableVC release];
and lastly, in the ViewDidLoad of the next view controller:
[self.navigationController setNavigationBarHidden:NO animated:YES];
in case your app needs a navigation controller for a specific section of the app but not all if it, you will need to use the VC to manage this, in a similar way the appDelegate manages the sample navigation based sample app.
i hope this helps anyone struggling with wrapping their minds around the design patterns implemented here.
cheers.

How do I make a reusable XIB with it's own UIViewController?

I am trying to create a reusable "picker". It is basically like a keypad of a phone. Since I will be using this a lot in my iPhone app, I have been frustrated with trying to make it appear.
It is in its own XIB file and has its own UIViewController subclass as the FileOwner.
However, when I instantiate this with:
MonthPickerViewController *mpvc
= [[MonthPickerViewController alloc] initWithNibName:#"MonthPicker"
bundle:nil];
Nothing happens on the screen. Yet is does fire the -viewWillAppear methods, etc.
So, what am I doing wrong either in code or in InterfaceBuilder that is preventing my view to appear?
Are you pushing the view controller?
[[self navigationController] pushViewController:mpvc animated:YES];
Or are you adding the view controller's view as a subView of your current view?
First, make sure you've hooked everything up right inside Interface Builder. An easy gotcha is to forget to connect the View object up to the view outlet of your UIViewController subclass.
Then, as Adam says, you need to actually display the view. Assuming you're doing this inside the code of another view controller, you'd need something like the following if you just wanted the new view to appear ontop of your current view:
[self.view addSubview:mpvc.view];
Of if you are using a navigation controller to stack views:-
[[self navigationController] pushViewController:mpvc animated:YES];