setViewControllers of UINavigationController crash app when use with animation:NO - iphone

this is working very fine:
[(UINavigationController*)viewController setViewControllers:[NSArray arrayWithObject:cvc] animated:YES];
But This cause my application to crash:
[(UINavigationController*)viewController setViewControllers:[NSArray arrayWithObject:cvc] animated:NO];
the same line I have used in else part with different viewController with animation:NO and it is working fine. Am I missing something or it is a bug?

If you are setting your view controller as rootViewController then do this
yourNavigationController=[[UINavigationController alloc]initWithRootViewController:cvc];
and then when you want to go to newViewController then use pushViewController
[self.navigationController pushViewController:yourViewObject animated:YES];

Apple has given the documentation of this function only with animation set to YES.
- (void)setViewControllers:(NSArray *)viewControllers animated:(BOOL)animated __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_3_0);
// If animated is YES, then simulate a push or pop depending on whether the new top view controller was previously in the stack.
I think when you set the animation to 'No' the new top-level NavigationController has not been initialized and loaded properly until the animation is done.

Related

Best way to switch View Controller in iOS

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

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....

Unable to get presentViewController to work

I copied a working viewcontroller class from another project into a new project. I can't get the view to load in the new project. In the old project I used presentModalViewController. In the new I cannot get the view to load using either presentModalViewController or presentViewController
I am trying to load the present the view from my main view controller.
Here is what my main view controller interface looks like...
// ViewController.h
#import <UIKit/UIKit.h>
#import "RequestDialogViewController.h"
#interface ViewController : UIViewController <RequestDialogViewControllerDelegate> {
}
- (void)requestDialogViewDidDismiss:(RequestDialogViewController *)controller withResponse:(NSString*)response;
I am using presentModalViewController like this...
RequestDialogViewController *requestIPViewController = [[RequestDialogViewController alloc] initWithNibName:#"RequestDialogViewController" bundle:nil];
navigationController = [[UINavigationController alloc] initWithRootViewController:requestIPViewController];
[self presentModalViewController:navigationController animated:YES];
and presentViewController like this...
RequestDialogViewController *requestIPViewController = [[RequestDialogViewController alloc] initWithNibName:#"RequestDialogViewController" bundle:nil];
[self presentViewController:requestIPViewController animated:YES completion:nil];
What am I missing in the new project? The init method fires, but viewDidLoad does not and nothing is displayed.
Thanks
If ViewController is the root view controller, it can't present a modal view controller from within its own viewDidLoad, because at that point it doesn't have information like the screen size.
If other view controllers have already displayed, this will work. If the root view controller is a UINavigationController, you will see a view sliding in from the right while the modal view slides up from the bottom.
Anyway, for your ViewController, the soonest you could present it is after it has become visible. Using a timer for this is unreliable; older and slower devices have dramatically longer load times.
For more reliability, implement viewDidAppear: for ViewController. Do still use your timer system to add an additional delay; a fraction of a second should be sufficient. Although presenting the modal view controller from within viewDidAppear worked for me in the iOS 5.1 simulator, Presenting a modal view controller when loading another ViewController says it sometimes doesn't happen.
I have it resolved. I was trying to present the view from view did load of the main view controller. Not sure why it does not work there, but instead I am now setting a timer which calls a method to present the view controller after the main view loads and it works fine now using...
[self presentViewController:requestIPViewController animated:YES completion:nil];
Thanks to those who replied.
As #Dondragmer said, if you want to present your viewController in root view's viewDidLoad, it will fail.Once your viewController is ready for that, you can present your new viewController.
So, you can do that in
- (void)viewDidLayoutSubviews {
//present here
}
I encountered the same problem. But my situation is the presentViewController is called after the dismissViewControllerAnimated for another ViewController. My solution is to move the presentViewController to completion block of dismissViewControllerAnimated.
Present a modalViewController:
For the benefit of all starting programmers, type it instead of copy paste.
myVC *viewController = [[myVC alloc]initWithNibName:#"myVC" bundle:nil];
viewController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:viewController animated:YES];
[viewController release];
It looks like you were trying to present a nav controller as a view controller in the first sample, then you were using the wrong method in the second one.

I can came back to first navigation control page with a button?

-(IBAction) btnReturn:(id) sender{
firstView * firstview =[[firstView alloc]initWithNibName:#"firstView" bundle:nil];
[self.view pushViewController:firstview animated:NO];
}
with the previsly code I see the first view but the navigation control increment. I wold came bak as was the navigation starting point. Any help?
pushViewController:animated: will add to the navigation stack; you want popViewControllerAnimated: to go back one view in the stack.
If you want to return to the very first (root) view controller, you want popToRootViewControllerAnimated:.
See: https://developer.apple.com/library/ios/#documentation/UIKit/Reference/UINavigationController_Class/Reference/Reference.html
In your above code you are pushing a controller on self.view (firstView, I am considering it as controller as you are creating it using initWithNibName: method, but you should you proper naming conventions to avoid confusions.) But view do not have any such method pushViewController:. Instead you sould use if you really have self (the controller in which you are using this IBAction) in navigation stack.
[self.navigationController pushViewController:firstview animated:NO];
To pop controller from navigation stack, follow what #gregheo suggested.
Try using popViewControllerAnimated instead:
- (IBAction)btnReturn:(id)sender
{
[self.navigationController popViewControllerAnimated:NO]; // Or Yes if you would like to have an animation.
}

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.