How to Dismiss 2 Modal View Controllers in Success

2019-01-11 02:41发布

问题:

I have 2 view controllers presented modally.

A presents B which presents C.

When I dismiss C I would like to dismiss B as well. But I am not sure how to do this:

Dismiss C:

[self dismissModalViewControllerAnimated:YES]
//[delegate dismissB] //this doesn't work either when i create a delegate pattern

Now I am left with B. How can I dismiss B from C?

回答1:

Try using the next code in B (right after dismissing C, as you already do):

[self.parentViewController dismissModalViewControllerAnimated:YES];

IMPORTANT:
Don't do anything in the method after this line.
This view controller (B) probably will be released and deallocated...

UPDATE:
Starting from iOS7 the method above is deprecated.
Use the next method instead:

[self.parentViewController dismissViewControllerAnimated:YES completion:^{ /* do something when the animation is completed */ }];


回答2:

Just found out you need to use presentingViewController in iOS 5.

[self.presentingViewController.presentingViewController dismissModalViewControllerAnimated:YES];

A -> B -> C

Running the above code in modal C will take you back to A



回答3:

This worked for me, very simple

// Call inside View controller C    
self.presentingViewController?.dismissViewControllerAnimated(false, completion: nil)
self.presentingViewController?.dismissViewControllerAnimated(true, completion: nil)

Explanation:

If you call dismiss on C, it can only remove C. If you call dismiss on B, it will do the right thing: Remove the topmost modal view controller. The first call therefore removes C (with no animation). The second call removes B.

The easiest way to access view controller B from C is to use the presentingViewController variable.



回答4:

In B. Put:

[self dismissModalViewControllerAnimated:NO];
[self dismissModalViewControllerAnimated:YES];

Only run one animation.



回答5:

Check this for swift:

self.presentingViewController?.presentingViewController?.dismissViewControllerAnimated(true, completion: nil);


回答6:

In swift 4

self.presentingViewController?.presentingViewController?.dismiss(animated: true, completion: nil);



回答7:

You only need one dismiss command. Just dismiss B, and then C will go away with it.



回答8:

I read all the topics and I didn't find a proper answer. If you dismiss B, than C will immediately disappear and create a weird effect. The proper way is to present C as a child view controller with custom animation from the bottom, like:

   [b addChildViewController:c];
    c.view.frame = CGRectOffset(b.view.bounds, 0, b.view.bounds.size.height);
    [b.view addSubview:c.view];
    [c didMoveToParentViewController:b];

    [UIView animateWithDuration:0.5 animations:^{
        c.view.frame = CGRectOffset(c.view.frame, 0, -b.view.bounds.size.height);
    } completion:^(BOOL finished) {

    }];

And then you simply dismiss B and it all looks much nicer!



回答9:

This worked for me:

// Swift
presentingViewController?.dismissViewControllerAnimated(true, completion: nil)

// Objective-C
[self.presentingViewController dismissViewControllerAnimated:true completion:nil];


回答10:

The navigation controller has a "viewControllers" property that is an array - you can set that to a new array minus the two view controllers you want to remove.



回答11:

Inspired by Albertos solution, I created a delegate method in B with a block to show a result of deleting an account:

#pragma - mark - AddAccountViewControllerDelegate Methods

- (void) dismissToSettings {
    [self dismissModalViewControllerAnimated:NO];
    [self dismissViewControllerAnimated:YES completion:^(void){[DKMessage showMessage:LS(@"Account was successfully created")];}];
}


回答12:

I faced the same problem, and a better solution was creating a "DismissViewProtocol" as follow:

File: DismissViewProtocol.h

@protocol DismissViewProtocol <NSObject>
-(void)dismissView:(id)sender;
@end

In my B-modal view, let's response for the delegate method:

in my b.h file:

#import "DismissViewProtocol.h"
@interface B-Modal : UIViewController <DismissViewProtocol>
...
@end

in my b.m file:

-(void) dismissView:(id)sender
{
 [((UIViewController *) sender) dismissModalViewControllerAnimated:NO];
 [self dismissModalViewControllerAnimated:YES];
}

In the same B-view controller, when I call the Next, in my B modal view, when I call the other modal view C, supposing that for segue:

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    ((C-ViewController *)segue.destinationViewController).viewDelegate=self;
}

Finally, in my c.h file, lets prepare for the delegate:

@property(nonatomic, weak) id <DismissViewProtocol> viewDelegate;

And in my c.m file, I just tell my viewDelegate to dismiss my modal view controller and itself:

-(void)closeBothViewControls
{
       [self.viewDelegate dismissView:self];
}

And that's it.

Hope it works for all of you.



回答13:

Here is a way how to dismiss more that one modal view controller using repeat cycle:

Swift 3

// In this example code will go throw all presenting view controllers and 
// when finds it then dismisses all modals.
var splitViewController: UIViewController? = self

repeat {
    splitViewController = splitViewController?.presentingViewController
} while (!(splitViewController is UISplitViewController) && (splitViewController != nil))

splitViewController?.dismiss(animated: true, completion: nil)