Best way to switch View Controller in iOS - iphone

I have 2 view controllers in my project. Inside View Controller1 I want to switch to View Controller 2 by press of a button. Currently I do this
- (IBAction)startController2:(id)sender {
viewController1 vc2 = [[viewController2 alloc] init];
self.view = vc2.view;
}
This seems to work fine, but there is a big delay (4 secs) between the button press and second view controller appears. If I call the viewController2 directly from the AppDelegate things load faster. What am I doing wrong here. Any help is greatly appreciated.

Several things to consider.
Part 1: "What am I doing wrong here"?
You definitely didn't mean to do self.view = vc2.view. You just put one view controller in charge of another view controller's view. What you probably mean to say was [self.view addSubview:vc2.view]. This alone might fix your problem, BUT...
Don't actually use that solution. Even though it's almost directly from the samples in some popular iPhone programming books, it's a bad idea. Read "Abusing UIViewControllers" to understand why.
Part 2: What you should be doing
It's all in the chapter "Presenting View Controllers from Other View Controllers".
It'll come down to either:
a UINavigationController, (see the excellent Apple guide to them here) and then you simply [navigationController pushViewController:vc2]
a "manually managed" stack of modal view controllers, as andoabhay suggests
explicitly adding a VC as child of another, as jason suggests

You should consider using UINavigationController to switch view controllers. If your building target is iOS 5.0+, you can also use the new controller container concept: [mainViewController addChildViewController:childViewController].

Use presentModalViewController as follows
[self presentModalViewController:vc2 animated:YES completion:^(void){}];
and in the viewController1 use
[self dismissModalViewControllerAnimated:YES completion:^(void){}];
where ever you want to go back to previous controller.

[aController presentViewController:bController animated:NO completion:nil];
[bController presentViewController:cController animated:NO completion:nil];
when you want dismiss cController, you can do like this
[aController dismissViewControllerAnimated:NO completion:nil];
this is the flow chart.
aController → bController → cController
↑___________________________↓

You should use UINavigationController to switch view controllers.
You are on View1 and add the following code on button click method.
View2 *View2Controller = [[View2 alloc] initWithNibName:#"View2" bundle:nil];
[self.navigationController pushViewController:view2Controller animated:YES];

Related

Trigger a seque from the AppDelegate to popup a view in the StoryBoard

I am trying to convert my App to a Storyboard, but am having some problems.
In de previous model I could have an 'actionClass' in my AppDelegate which I called when I needed to pop-up a view.
E.g.
DOArticleViewController *articleView = [[DOArticleViewController alloc] initWithArticle:article notification: notification nibName:#"DOArticleViewController" bundle:nil];
[[self navigationController] pushViewController:articleView animated:YES];
But now with the storyboard it does not work anymore.
Then I tried the following code in the AppDelegate:
id currentController = [[[[self window] rootViewController] navigationController] visibleViewController];
[currentController performSegueWithIdentifier:#"settingsSeque" sender:nil];
Don;t think this is the best anyway, as only the rootViewController has all the seques needed, and might not be the visibleViewController, but one step at a time.
With this the only thing I see happening is the message and no action:
Unbalanced calls to begin/end appearance transitions for UINavigationController: 0xb428e00.
I spend a view hours now on trying to figure out to get this to work, but am realising that it might be better to go back to the traditional independent XIB files....
I solved with the answer given in this question: ios: Accessing a navigation controller from app delegate
I tried to get the Navigation Controller, but this was nil and I didn't realise it.
My navigation controller was the rootViewController, so that is also the NavigationController.
Casting the rootViewController to NavigationController and invoking 'visibleViewController' worked fine after that!

Go to first view controller in app

I need to go to the first view in my app. I have a few views pushed onto the stack then a modal navigation controller and more views pushed onto that.
The problem I'm having is that using [[self navigationController] popToRootViewControllerAnimated:YES]; only goes back to the first view in the modal stack.
And I can't get [[self navigationController] popToViewController:.. to work because the true first view controller isn't accesible with [[self navigationController] viewControllers].
Any ideas on how to accomplish this? Thanks.
Do this:
[[self navigationController] dismissModalViewControllerAnimated:YES];
That will get you back to the VC that modally presented the navigation controller. Getting farther back after that depend on how you pushed those "few views" before the navigation controller.
Edit - explanation to get to the deepest root...
It sounds like those "few views" are on another, underlying navigation controller's stack. This can be a little tricky, because the clean way to get farther back in that stack is to have that underlying navigation controller pop to it's own root. But how can it know that the modal VC on top of it is done?
Let's call the view controller that did the modal presentation of second navigation controller VC_a. It's a modally presented navigation controller whose topmost VC is VC_b. How can VC_a know to pop to it's navigation root when VC_b modally dismisses itself?
The good answer (usually) is that VC_b decided to dismiss itself for a reason - some condition in your app/model changed to make it decide to be done.
We want VC_a to detect this condition, too. When VC_b gets dismissed, and VC_a gets a viewWillAppear message because it's about to be uncovered:
// VC_a.m
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
if (/* some app condition that's true when VC_b is done */) {
// I must be appearing because VC_b is done, and I'm being uncovered
// That means I'm done, too. So pop...
[self.navigationController popToRootViewControllerAnimated:NO];
} else {
// I must be appearing for the normal reason, because I was just pushed onto the stack
}
}
You need to do it by using the delegation pattern. Specifically, by creating a protocol that implements the delegate's respondsToSelector method.
See this post for complete details. It should be almost exactly what you are looking for. I had to do something similar, except I only needed to pop one view off the navigation stack instead of using popToRootViewControllerAnimated:.
For iOS6...
[self.view.window.rootViewController dismissViewControllerAnimated:YES completion:nil];
In AppDelegate.m class create method with bellow flow...
-(void)MethodName{//your method name
YourViewController *objViewController = [[[YourViewController alloc] initWithNibName:#"YourViewController" bundle:nil] autorelease]; ///define your viewcontroller name like "FirstViewController"
UINavigationController *yourNavigationController = [[[UINavigationController alloc] initWithRootViewController:objViewController] autorelease];
self.window.rootViewController = yourNavigationController;
}
When you want redirect on firstview just call this method from appdelegate object....

Kill View and back to rootViewController

I am new to IOS, sorry in advance if I ask a stupid question.
I use UITabBarController and navigationController to control view.
At my last view, I would like to have a button when the button is pressed, view will return to rootViewController which I set by MainWindow.xib file and kill any process which run in app background.
this is my code in the last view before I want to back to rootViewController:
-(IBAction)doneButtonPressed:(id)sender{
JourneyIndexViewController *journeyIndexVC = [[JourneyIndexViewController alloc] initWithNibName:#"JourneyIndexViewController" bundle:nil];
[journeyIndexVC setDistanceLabelValue:self.distanceLabelValue];
[self.navigationController pushViewController:journeyIndexVC animated:YES];
[journeyIndexVC release];
[self dismissModalViewControllerAnimated:YES];
}
JourneyIndexViewController is the rootViewController that I set in MainWindow.xib.
Thank you very much for your advance support.
try
[self.navigationController popToRootViewControllerAnimated:YES];
You should take a look at this: UINavigationController Class Reference for better understanding
I am making a few assumptions here, but if JourneyIndexRootViewController is your rootViewController and is created in IB (in a nib), you do not need to re-crete it when pushing the button. It sounds like you simply need to remove the UINavigationController that you added on top of the rootViewController.
Try this. This should pop you back to the Previous View Controller.
[self.navigationController popViewControllerAnimated:NO];
Hope this helps

Dismiss ModalViewController from another viewController in subview

I've got a view called A open with presentModalViewController Method, inside this view I loaded secondary view using:
new_view = [[new_websongs alloc] initWithNibName:#"new_websongs" bundle:nil];
[mysubview addSubview:new_view.view];
ok, to here it's ok but now I need to dismiss the first view "A" calling a method [self dismissModalViewControllerAnimated:YES] situated if first "A" viewController from secondary view controller (new_view) but not work! the code is:
self.Aviewcontroller = [[Aview alloc] init];
[Aviewcontroller dismissModalViewControllerAnimated:YES];
[Aviewcontroller release];
Please help ME!!!!
Thanks
Did u try [self.parentViewController dismissModalViewControllerAnimated:YES];
You have a logical problem. Start reading View Controller Programming Guide for iOS
The view controller that present an modal view controller must dismiss it or the modal view controller must dismiss it self
Totally agree with other answers; think logically about the order of view controller order and type. So think about which controllers are shown modally, and those shown via a navigation controller.
You can of course set a number of view controllers with:
- (void)setViewControllers:(NSArray *)viewControllers animated:(BOOL)animated
without animation, then when required call say:
- (NSArray *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated
to show a specified view controller further up your stack of view controllers.
Hope this helps think about what you need to do? It's often a good idea to think about the order and type of view controllers in your app's interface in a separate project - where you can try it out on the device itself.
try this it should work
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
This works if you are presenting a modal view from a UISplitViewController. It can also be applied in so many other ways...
First, create an instance in your .h file for your appDelegate, (AppDelegate_iPad *appDelegate) then put this in your viewDidLoad or comparable method:
ipadDelegate = (AppDelegate_iPad *)[[UIApplication sharedApplication] delegate];
Now, present the first modal view like this:
YOURVC *vc = [[YOURVC alloc] initWithNibName:#"YOURVC" bundle:nil];
[ipadDelegate.splitViewController presentModalViewController:vc animated:YES];
[vc release];
Say you have a subview, like a UITableView, and want to dismiss the modal from the didSelectRowAtIndexPath. All you have to do to dismiss your modal with a subview is create another ipadDelegate instance inside your subview's .h (if needed), reference the [[UIApplication sharedApplication] delegate] again, and dismiss:
[ipadAppDelegate.splitViewController dismissModalViewControllerAnimated:YES];
Essentially, as long-winded as it may be, use your appDelegate's controller to present and dismiss the the modal if you need to maintain a persistent reference to the presentingViewController...because all the things above just don't work in my case.
If you're presenting with your ipadDelegate, make sure you check the mode of presentation in your MainWindow_iPad.xib. Your "Transition Style" should be "Cover Vertical" and "Presentation" should be "Current Context" or your modal may present behind other views.

Showing a modal view controller from a tab bar app

First, I would like to warn that I am a complete newbie into iPhone coding...
I need to show up a viewcontroller from a library, I know that it is modal. I have a tab bar app (created with the default XCode template). I need to show that viewcontroller, there are no problem if it hides the tabbar itself... But I am quite clueless, I don't know even what to search, or what to read...
You can call presentModalViewController:animated: to display another UIViewController modally.
EDIT: If you want to display your modal view in response to a button touch (for example), you would display it like this:
- (IBAction)buttonTouched:(id)sender
{
ModalViewController* controller = [[ModalViewController alloc] init];
[self presentModalViewController:controller animated:YES];
[controller release];
}
Then when you want to dismiss the modal controller, call dismissModalViewControllerAnimated:. This can be called either on your main view controller, or the modal one.
I don't know even what to search, or
what to read...
View Controller Programming Guide is a good place to start to help you understand view controllers (including modal ones). If that's confusing, get a bigger picture with iOS Application Programming Guide or start at the very beginning.
You can call modal view as
YourViewController *yvc = [[YourViewController alloc] initWithNibName:#"YourViewController" bundle:YES]
[self presentModalViewController:yvc animated:YES];
You can call it in the IBAction method in case you want to call it on any control event like Button Click
-(IBAction)buttonClicked:(id)sender
{
YourViewController *yvc = [[YourViewController alloc] initWithNibName:#"YourViewController" bundle:YES]
[self presentModalViewController:yvc animated:YES];
}
You can call it using self.
Hope this helps you.
If you have more doubts on this then you can ask me.