I set up a mechanism where a modal view controller can be dismissed by tapping the outside of the view. The set up is as follows:
- (void)viewDidAppear:(BOOL)animated
{
UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapBehind:)];
[recognizer setNumberOfTapsRequired:1];
recognizer.cancelsTouchesInView = NO; //So the user can still interact with controls in the modal view
[self.view.window addGestureRecognizer:recognizer];
}
- (void)handleTapBehind:(UITapGestureRecognizer *)sender
{
if (sender.state == UIGestureRecognizerStateEnded)
{
CGPoint location = [sender locationInView:nil]; //Passing nil gives us coordinates in the window
//Then we convert the tap's location into the local view's coordinate system, and test to see if it's in or outside. If outside, dismiss the view.
if (![self.view pointInside:[self.view convertPoint:location fromView:self.view.window] withEvent:nil])
{
[self dismissModalViewControllerAnimated:YES];
NSLog(@"There are %d Gesture Recognizers",[self.view.window gestureRecognizers].count);
[self.view.window removeGestureRecognizer:sender];
}
}
}
This works amazing for dismissing a single modal view. Now suppose I have two modal views, one called from within the root view controller (View A) and then another modal called from within the first modal (View B)
Kind of like this:
Root View -> View A -> View B
When I tap to dismiss View B, all is well. However I get an EXC_BAD_ACCESS error when I try to dismiss View A. After turning on zombies, it seems that View B is still getting the message handleTapBehind: sent to it, even though it’s been dismissed and out of memory after View B was closed.
My question is why is View B still being messaged? (handleTapBehind: make sure that gesture recognizer should have been removed from the associated window.) And how can I get it to be sent to View A after View B is already dismissed.
PS. The code above appears both inside the controller for View A and for View B, and it is identical.
EDIT
Here’s how I am calling the modal view controller, this code is inside a view controller that is within the standard view hierarchy.
LBModalViewController *vc = [[LBModalViewController alloc] initWithNibName:@"LBModalViewController" bundle:nil];
[vc.myTableView setDataSource:vc];
[vc setDataArray:self.object.membersArray];
[vc setModalPresentationStyle:UIModalPresentationFormSheet];
[vc setModalTransitionStyle:UIModalTransitionStyleFlipHorizontal];
[vc.view setClipsToBounds:NO];
[self presentViewController:vc animated:YES completion:nil];
// This is a hack to modify the size of the presented view controller
CGPoint modalOrigin = vc.view.superview.bounds.origin;
[[vc.view superview] setBounds:CGRectMake(modalOrigin.x, modalOrigin.y, 425, 351)];
[vc.view setBounds:CGRectMake(modalOrigin.x, modalOrigin.y, 425, 351)];
That’s pretty much it, everything else is pretty standard.
Should be:
else you will get undefined results.