I have a view (viewB) that is pushed in using the navigation controller from another view (viewA) using pushViewController as usual, however for some reason, I want viewB's controller to pop the view using [self.navigationController popViewControllerAnimated:YES]; from inside its viewDidLoad method or viewDidAppear method, but none of them works, i.e. nothing happens (there is no crash in the app), however, i have a UIButton in viewB with IBAction that simply calls [self.navigationController popViewControllerAnimated:YES]; if the button tapped it will work and the view is popped off to the previous view !! this IBAction works if I removed [self.navigationController popViewControllerAnimated:YES]; from viewDidLoad or viewDidAppear methods because the popping will release the current view and all of its sub-views from memory.
the question is how can get the current view (viewB) to be popped off to the previous view (viewA) from inside viewDidLoad or viewDidAppear methods ?
thanks you so much in advance.
Try making method
- (void)popSelf {
[self.navigationController popViewControllerAnimated:YES];
}
In viewDidAppear add
[self performSelector:#selector(popSelf) withObject:nil afterDelay:0.0f];
This will add selector to runloop, so it will be performed after viewDidAppear.
Related
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....
I don't know why dismissViewControllerAnimated:completion:. I just want to do it.
I start with a
[self performSegueWithIdentifier:#"my_segue" sender:self];
But is I call the dismiss than nothing happens. I can create another segue, but it create a new view controller.
My question is: How dismiss the performSegueWithIdentifier:sender:?
Do you have a navigationBar in the viewController that's calling:
[self performSegueWithIdentifier:#"my_segue" sender:self];
If so, you'll need to use:
[self.navigationController popViewControllerAnimated:YES];
to pop the view off the stack. There's one segue call, but the framework seems to call:
presentViewController:animated:completion:
or:
pushViewController:animated:
as appropriate.
Ray
You could just call
[self dismissViewControllerAnimated:YES completion:nil];
from the view controller since the view controller was pushed by segue.
[my_segue_view_controller dismissModalViewControllerAnimated: YES] ?
(not sure, but it works in my practice)
performSegueWithIdentifier:sender: itself isn't dismissed, that's just the method that's called to initiate a named segue. What happens in the segue is of more interest.
You're right that you should call dismissViewControllerAnimated:completion:, and it should be called by the presenting view controller, which has previously called the presented view controller using presentViewController:animated:completion:. For more info, see the UIViewcontroller docs.
Use the below code for Swift 4 version
self.navigationController?.popViewController(animated: true)
I have a Navigation Controller that is presented modally with 4 views in the stack. The final view has a done button that dismisses the modal view. When I then present the modal view again, it automatically goes to that last view instead of the first one. I added a line to pop to first view after dismissed but it adds a weird animation whether I set it to YES or NO. Maybe I'm doing it wrong?
- (void)dismissModalView
{
[self dismissModalViewControllerAnimated:YES];
[self.navigationController popToViewController:[self.navigationController.viewControllers objectAtIndex:([self.navigationController.viewControllers count] -4)] animated:YES];
}
Update:
This is the method used to present the modal view/navcontroller
- (void)showModalView
{
self.optionsNavController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self.navigationController presentModalViewController:self.optionsNavController animated:YES];
}
No, it looks right. If you want to retain the state of the Navigation controller then don't present it modally as it will get deallocated when you dismiss the view.
Modal views are usually used to present information that only needs to be shown briefly without maintaining the state of the view (i.e. about page, login page, settings page, etc).
Excuse me if I'm oversimplifying your issue, but if your need is to pop straight back to the first view controller, perhaps you could give the popToRootViewControllerAnimated: method a try instead of popToViewController:.
I'm not sure what the problem with the dismiss code you posted is, but the following should work:
- (void)showModalView
{
self.optionsNavController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self.optionsNavController popToRootViewControllerAnimated:NO];
[self.navigationController presentModalViewController:self.optionsNavController animated:YES];
}
Also, viewDidLoad is intended to only be called once every time the view is loaded, viewWillAppear a
I have found a strange behaviour when trying to push a viewcontroller onto the stack. The following works fine:
[self.navigationController pushViewController:myViewController animated:YES];
but if I change it to animated:NO it no longer works, doesn't seem to push at all. I was performing this in a viewWillAppear but I have also tried it in viewDidAppear but with no luck.
Any ideas what could be causing this?
Thanks
The problem is most probably not the call itself, but the placement of the call. Try putting the same action on a UIButton and it should 100% work. I've noticed that putting view controller manipulation routines like presentModal... and pushViewController... don't sometimes work in the viewWill* viewDid* methods. Or try making the calls from those functions with a performSelector:withObject:afterDelay after a short delay and see if that works.
Edit: there are a couple of ways of doing what you want to do. You can directly modify the navigation stack of a navigation controller, so when you are in view N+1, you can replace view N on the stack (by building a new navigation stack array and setting it in to the navigation controller), then pop, and you'll get the effect of "popping back to a different view controller". You can also issue multiple pops and pushes from the view controller you want to leave, but you have to be careful:
// pop back 2 controllers on the stack to the setup screen
//
// locally store the navigation controller since
// self.navigationController will be nil once we are popped
//
UINavigationController *navController = self.navigationController;
// retain ourselves so that the controller will still exist once it's popped off
//
[[self retain] autorelease];
// Pop back 2 controllers to the setup screen
//
[navController popViewControllerAnimated:NO];
[navController popViewControllerAnimated:YES];
i have a root view controller that inserts a subview at index 0 at its viewDidLoad method.
i am trying to get the subview to become firstResponder, but can only do this - from my understanding - in the subview's viewDidAppear method.
here's the line of code i added to the root view controller's viewDidLoad method:
[self.view insertSubview: subViewController.view atIndex: 0];
the subviewcontroller has a xib, subViewController.xib, that is shown correctly at runtime. nevertheless, the subViewController's viewDidAppear does not get triggered.
any idea why this happens? any idea how to remedy this - apart from calling viewDidAppear manually (doing so results in failure to become firstResponder)?
thanks,
mbotta
You have to push the view controller on to a navigation stack in order for it's delegate methods to get called. Adding your view controller's view to the subview array won't call them. The first thing you should do is read the View Controller Programming Guide from Apple as this will save you from some headaches you're creating by doing this in a non-standard way.
Instead of adding the view to your root view controller subviews, do this:
SubviewController *controller = [[SubviewController alloc] init];
[[self navigationController] pushViewController:controller animated:YES];
[controller release], controller = nil;
Now your delegate methods will get called. If you don't have a navigation controller as your root view controller, though, this won't work.
If I recall correctly (sorry can't find the place in docs now) -viewDidAppear does not get called for subviews. You must call it manually in the -viewDidAppear method of parent view controller.