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.
handleTapBehindbeing sent to an already dismissed view. Nothing else besides the tap gesture has that selector set as the target. My suspicion is I have two tap gestures on top of each other and a single tap triggers them both. I tried to cycle through the array of them and disable all except the one I want to use, but that didn't work. - Andrew Lauer Barinov