MhaW MhaW - 4 months ago 38
iOS Question

dismissViewControllerAnimated:completion: not executed

When I call

dismissViewControllerAnimated:completion:
to dismiss a
UIViewController
the completion block is never executed when the corresponding view is in the middle of being animated onto the screen (using
presentViewController:animated:completion:
).

The
UIViewController
does not even dissappear. It is like
dismissViewControllerAnimated:completion:
is being ignored.

The following code is a simplified code example because the original is much bigger. The code I have given below simulates a use-case where a network communication error might trigger a view to popup whilst another view is also being popped-up at the same time..

Code example:

NSLog(@"Presenting view");

[self presentViewController:changeLocationViewController animated:YES completion:^{
NSLog(@"View done presenting");
}];

NSLog(@"Dismissing view");

[self dismissViewControllerAnimated:NO completion:^{
NSLog(@"View done dismissing");
}];


Log output is:


2013-08-28 16:14:12.162 [1708:c07] Presenting view

2013-08-28 16:14:12.178 [1708:c07] Dismissing view

2013-08-28 16:14:12.583 [1708:c07] View done presenting




Does anyone know how to dismiss the
UIViewController
in these circumstances?

Thanks in advance.

Answer

The reason this code snippet isn't working is because the completion block in these methods are executed at a later time after the animations have completed. You can see this in your logs: "Dismissing view" happens before "View done presenting". Try this instead:

NSLog(@"Presenting view");

[self presentViewController:changeLocationViewController animated:YES completion:^{
    NSLog(@"View done presenting");
    NSLog(@"Dismissing view");

    [self dismissViewControllerAnimated:NO completion:^{
        NSLog(@"View done dismissing");
    }];
}];

EDIT:

If you need to make sure the view is dismissed when the network error happens, try setting a boolean instance variable called networkErrorFound.

When you finish the network connection, set this to YES if an error happens. Then use this code:

[self presentViewController:changeLocationViewController animated:YES completion:^{
    NSLog(@"View done presenting");
    NSLog(@"Dismissing view");

    if (self.networkErrorFound) {
        [self dismissViewControllerAnimated:NO completion:^{
            NSLog(@"View done dismissing");
        }];
    }
}];

That way, it'll wait until it's done presenting to dismiss. You would also need to handle the case that the error happens after the animation is done (for instance, a slow connection that eventually fails), but that's outside the scope of this question.