I have three ViewControllers and its order is (A present B which presents C),
when I stay in the C viewController ,I have to dismiss ViewController to B viewController.
for C viewController ,its presentingViewCOntroller is B viewController
of course ,I can use
[self dismissViewControllerAnimated:YES completion:NULL];//self means C ViewController
But I was wondering I can also use the following method:
[self.presentingViewController dismissViewControllerAnimated:YES completion:NULL];
because the presentingViewController of C is B ViewController, but it did the same effect.
self means C ViewController while self.presentingViewController means B ViewController,but they also did the same work
The second question is I cannot use the following to dismiss two viewController in succession:
[self dismissViewControllerAnimated:YES completion:^{
[self.presentingViewController.presentingViewController dismissViewControllerAnimated:YES completion:NULL];
}]; //self means C viewController
Thanks for your help!
of course ,I can use
[self dismissViewControllerAnimated:YES completion:NULL];//self means C ViewController
This only dismisses C, not B as you seem to want.
But I was wondering I can also use the following method:
[self.presentingViewController.presentingViewController dismissViewControllerAnimated:YES completion:NULL];
Yes, this works. When in doubt, try it out.
The second question is I cannot use the following to dismiss two viewController in succession:
[self dismissViewControllerAnimated:YES completion:^{
[self.presentingViewController.presentingViewController dismissViewControllerAnimated:YES completion:NULL];
}]; //self means C viewController
That's not a question. Anyway, the reason it doesn't work is that after you dismiss yourself, your presentingViewController is nil. You need to store it in a temporary variable.
UIViewController *gp = self.presentingViewController.presentingViewController;
[self dismissViewControllerAnimated:YES completion:^{
[gp dismissViewControllerAnimated:YES completion:nil];
[self.presentingViewController.presentingViewController dismissViewControllerAnimated:YES completion:nil];
}];
Of course, the two will have different animations, you'll need to decide which you prefer.
see documentation:
The presenting view controller is responsible for dismissing the view
controller it presented. If you call this method on the presented view
controller itself, it automatically forwards the message to the
presenting view controller.
Please check: self.presentingViewController.presentingViewController is A viewController or not.
if not, I think you need use delegate or handler.
In my case, I used a tabbarcontroller as a rootViewController. When I used self.presentingViewController.presentingViewController, I got rootViewController (tabbarcontroller) which it have no response to presentingViewControler method.
Related
I have a UiViewController A which opens a second UIViewController B as follows:
BViewController *BController = [Utilities getMainStoryBoardWithIdentifier:#"BViewController"];
[self presentViewController:webViewController animated:YES completion:nil];
Now on UiViewController B, when I want to close it, I would like to close the A also. So I'm using the following:
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
[self dismissViewControllerAnimated:YES completion:nil];
But only the B is closing...
Any idea ?
Can you please try following code :
[self dismissViewControllerAnimated:YES completion:nil];
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
Where self is your B controller. I've just tried the code and it works well. Tell me if any other help is needed.
Try using an unwind segue.
If you have X which presents A, which in turn presents B, add
func unwindToX(_ segue: UIStoryboardSegue) { }
to view controller X
Then in your storyboard, drag from the close button in B to it's exit and select unwindToX. Clicking the button will then dismiss both view controllers. This also works with view controllers pushed on to a nav stack, or a combination of both.
EDIT Problem reinstated from scratch.
I have a ViewController A which has a Navigation Bar Button which presents an UIImagePickerController of sourcetype UIImagePickerControllerSourceTypeCamera, we'll call this ViewController B. In the didFinishPickingMediaWithInfo: method of A, I then present ViewController C.
The problem now starts here. When I finally reach C, we can see that view stack is clearly:
A -modal-> B -modal-> C
From C I then have a "Back" button present on the navigation bar which should take me back to B. However, since B is an UIImagePickerController, I cannot reuse it and it must be dismissed. So, to make this happen, I currently have the following method executing for that "Back" button on C:
- (IBAction)backOnPost:(UIBarButtonItem *)sender
{
[self.view endEditing:YES];
UINavigationController *LogControl = [self.storyboard instantiateViewControllerWithIdentifier:#"LogControl"];
RGLogViewController *logView = (RGLogViewController *)LogControl.topViewController;
[UIView animateWithDuration:0.25 animations:^{
self.presentingViewController.view.alpha = 0;
[self.presentingViewController dismissViewControllerAnimated:NO completion:nil];
[self.presentingViewController.presentingViewController dismissViewControllerAnimated:NO completion:nil];
} completion:^(BOOL finished){
[logView setBoolBackPushed];
}];
}
The above code works in that it takes me back to A by dismissing B and C. However, you can still see the transition because of a bit of "black-screening" from the dismissal of the two ViewControllers. You can see in the completion block [logView setBoolBackPushed];, this sets a static BOOL variable to true so that the beginning of A's viewWillAppear: presents a new UIImagePickerController immediately - the method looks like this:
- (void)viewWillAppear:(BOOL)animated
{
NSLog(#"HERES postBackButtonPushed:%hhd", postBackButtonPushed);
if(postBackButtonPushed == true)
{
self.view.hidden = YES;
self.navigationController.navigationBar.hidden = YES;
self.tabBarController.tabBar.hidden = YES;
UIImagePickerController * imagePicker = [[UIImagePickerController alloc] init];
imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
imagePicker.delegate = self;
[self presentViewController:imagePicker animated:NO completion:^{}];
}
This is currently how I am getting the following desired effect: Go from A to the camera (B), to C and then back to a new camera which is our new B. This is achieved w/ almost perfect seamless transitions.
Im still having problems with being able to slightly see the transitions. Another problem is the timing. This collaboration of dismissing and presenting ViewControllers takes more time than I would like it to. It's almost instantaneous, but I would like something better. What should I do and am I doing something wrong?
there are some possible cases that cause your problem :
presenting B after A and then presenting C is a bit strange behaviour for both UX/UI and by code. Either push B from A and then present C over B OR dismiss A, present B, dismiss B, present C.
there are completion methods and you are not using them. your code show that you call dismissViewControllerAnimated twice for C and B for ex. you should handle presenting and dismissing order. I think iOS 8.2+ or 8.3+ start to handle them more efficiently. And if there is an error, it will crash after this version.
imagepicker controller cause this error while dismissing VCs in different ways. For ex. showing alert popup before presenting a VC can cause also a crash.
I believe this will work for you.
Do!
[self.presentingViewController dismissViewControllerAnimated:NO completion:^{
[RefrenceOfPreviousViewController dismissViewControllerAnimated:YES completion:^{
}];
}];
Instead of
[self.presentingViewController.presentingViewController dismissViewControllerAnimated:NO completion:nil];
I am developing an app that as first viewcontroller has an UIViewController.
This controller pushes a NavigationViewController that contains other controllers.
Now I need to pop the RootViewController of the NavigationController to go back to the initial UIViewController.
I tried with
[self dismissViewControllerAnimated:YES completion:nil];
and the app crashes("Tread1:EXC_BAD_ACCESS(code=1, address= ......)").
I tried with
[self.navigationController popViewControllerAnimated:YES];
and nothing happens.
The initial UIViewController calls
[self performSegueWithIdentifier:#"MyIdentifier" sender:self];
In the UIBuilder the segue is of type "Show(e.g. Push)"
Then I have a NavigationViewcontroller that contains the RootViewController and another Viewcontroller.
What I am trying to achieve is to go back to the first viewcontroller (the one outside the navigationcontroller) from the RootViewController. So I should have the navigationcontroller there.
What am I missing?
Apparently I had a couple of GestureRecognizer still in place that were causing the crash of the app.
The right method was:
[self dismissViewControllerAnimated:YES completion:nil];
Im trying to dismiss a ModaViewController called C, back to A. The ModalViewController is presented in B. Therefore the Navigation flow is A->B - (present ModalView) -> C. I am able to dismiss the ModalViewController back to B, but I am unable to pop back to A in the completion bracket. This is the code I have tried:
[self dismissViewControllerAnimated:YES completion:^{
[self.navigationController popToViewController:[[self.navigationController viewControllers] objectAtIndex:0] animated:YES];
}];
The ModalViewController is dismissed but does not pop back to A. I call this block of code in an IBAction.
Any advice?
On a second note, when I dismiss the ModalViewController all my UIPickers in Controller B are empty/ deallocated. I am using ARC as well.
The problem with your code is that self.navigationController will be nil. If you have a controller (A) embedded in a navigation controller, and that controller pushes to another controller (B) which then presents your last controller (C), then you need to do something like this,
-(IBAction)dismissToBThenPop:(id)sender {
UINavigationController *nav = (UINavigationController *)self.presentingViewController;
[self dismissViewControllerAnimated:YES completion:^{
[nav popViewControllerAnimated:YES];
}];
}
Even though you present C from B, the actual presentingViewController will be the navigation controller. This code will dismiss C then pop B, but you will see B for an instant before ut pops back to A. If you don't want to see this, then you should use an unwind segue to go directly back to A from C.
Your second problem about the pickers being empty and deallocated should not be happening under the scenario that you say you have. You will have to provide more information about what you're doing in B to solve that problem.
Create a protocol in ModalViewController, let's say ModalViewControllerDelegate with a method -(void)dismissTheModal, and make B implement this protocol. Before showing the ModalViewController, do modalViewController.delegate = self. When you're IBAction is called, do [self.delegate dismissTheModal], and in controller B you should do :
-(void)dismissTheModal {
[self dismissViewControllerAnimated:YES completion:^{
[self popViewController];
}];
I try 2 ways to dismissed 2 viewcontrollers consecutively but only one of them got dismissed not the second one
method1
-(void) LoginDone:(NSNotification *)notif
{
[self dismissViewControllerAnimated:YES completion:NULL]; //previous viewcontroller
[self dismissViewControllerAnimated:YES completion:NULL]; //current viewcontroller
}
method2
-(void) LoginDone:(NSNotification *)notif
{
[self dismissViewControllerAnimated:YES completion:NULL];
[[NSNotificationCenter defaultCenter] postNotificationName:#"LoginDone2" object:nil];
}
-(void) LoginDone2:(NSNotification *)notif
{
[self dismissViewControllerAnimated:YES completion:NULL];
}
I need to find out a way to dismiss both the previous viewcontroller and current viewcontroller consecutively.
This is now an old question, but it seems to be exactly the problem I am having presently.
Here what I did:
[self.presentingViewController.presentingViewController
dismissViewControllerAnimated:YES completion:nil];
And it works for me. I hope it can be useful to someone.
By calling
[self dismissViewControllerAnimated:YES completion:NULL];
you are telling self to dismiss the view it presented. Telling twice the same self object to dismiss the view it presented, will not change the result. In other words self cannot represent the "current view" and the "previous view" at the same time as per your comment to the code. self is just a single controller representing a single view, either the current or the previous one.
To fix this, you should send the dismissViewControllerAnimated to self (that presented the top-most view, I assume) and to the other view controller object that presented the previous view.
In other words, I would expect something like this:
-(void) LoginDone:(NSNotification *)notif
{
[self dismissViewControllerAnimated:YES completion:NULL];
[self.previousController dismissViewControllerAnimated:YES completion:NULL];
}
Actually, you could send just one message to the second view controller and both views would be dismissed (source):
If you present several view controllers in succession, and thus build a stack of presented view controllers, calling this method on a view controller lower in the stack dismisses its immediate child view controller and all view controllers above that child on the stack. When this happens, only the top-most view is dismissed in an animated fashion; any intermediate view controllers are simply removed from the stack. The top-most view is dismissed using its modal transition style, which may differ from the styles used by other view controllers lower in the stack.
I know this is an old question but maybe somebody will look for solution on this issue so here it is:
-(void) closeModalViews
{
[previousVC dismissViewControllerAnimated:YES completion:^(void) {
[self dismissViewControllerAnimated:YES];
}];
}
I like JPetric's idea, but first you must dismiss the current view controller's view and only then can you dismiss the presenting view controller's view.
[self dismissViewControllerAnimated:NO completion:^(void) {
[self.presentingViewController dismissViewControllerAnimated:NO completion:nil];
}];
As far as I could understand you are trying something like below:
There are 2 view controllers.
You want both of them to be vanished.
Another controller comes in.
But the fact is only one controller is displayed, why you would need to dismiss 2 then?
You can use self.view.hidden=true; on the jumped viewcontrollers while animating back to the first viewcontroller. Using [self.presentingViewController dismiss...] is not working for me without hiding.