How to remove gesture recogniser

SO, I am adding a gesture recogniser to an overlay view. When tapped on screen i want this overlay to go away. Having said that adding a gesture recognizer overrides the "touch up inside" and other button click events. I need this back therefore i need to removegesturerecognizer. I can use this method however i have a problem. My code below -

- (void)helpClicked
{
    CGRect visibleBounds = [self convertRect:[self bounds] toView:viewContainer];
    CGFloat minimumVisibleX = CGRectGetMinX(visibleBounds);
    UIImageView * helpOverlay = [[UIImageView alloc]initWithFrame:CGRectMake(minimumVisibleX, 0, 1024, 768)];
    UIImage * helpImage = [UIImage imageNamed:@"HelpOverLay.png"];
    [helpOverlay setImage:helpImage];
    helpOverlay.tag = 50;
    self.scrollEnabled = NO;
    [self addSubview:helpOverlay]; 
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] 
                               initWithTarget:self
                               action:@selector(dismissView)];

[self addGestureRecognizer:tap];    

}

Here i am taking the overlay off the other view.

- (void) dismissView
{
    UIView *overlay = [self viewWithTag:50];
    [overlay removeFromSuperview];
    self.scrollEnabled = YES;
}

My question is how do i remove the gesture recognizer in the second method? I cant pass the variable tap into this method nor can i remove it in the previous method either. Any pointers? Ive been stuck with quite a lot of passing variable problems when it comes to events.


Solution 1:

This loop will remove all gesture recognizers a view has

for (UIGestureRecognizer *recognizer in self.view.gestureRecognizers) {
    [self.view removeGestureRecognizer:recognizer];
}

Solution 2:

From the WWDC 2015, Cocoa Touch Best Practices, it is suggested that you keep a property or iVar if you need to access it later, and don't go with using viewWithTag:.

Moto: Properties instead of Tags

This saves you from some trouble:

  1. When dealing with multiple gestures, you remove the gesture that you want directly with accessing the property and remove it. (Without the need to iterate all the view's gestures to get the correct one to be removed)
  2. Finding the correct gesture by the tag when you are iterating, is very misleading when you have multiple tags on views, and when having conflicts with a specific tag

(i.e) You implemented it first time with tags, and everything works as expected. Later you work on another functionality which lets say breaks this and causes undesired behavior that you don't expect it. Log doesn't give you a warning, and the best thing you can get depending on the case it's a crash signalizing unrecognized selector sent to instance. Sometimes you won't get any of these.

Solution

Declare the iVar

@implementation YourController {
    UITapGestureRecognizer *tap;
}

Setup your view

- (void) helpClicked {
    //Your customization code

    //Adding tap gesture
    tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissView)];
    [self addGestureRecognizer:tap];
}

Remove the gesture directly

- (void) dismissView {
    [self.view removeGestureRecognizer:tap];
}

Solution 3:

Declare an ivar UITapGestureRecognizer *tap in your @interface.

Change helpClicked to:

- (void)helpClicked
{
    CGRect visibleBounds = [self convertRect:[self bounds] toView:viewContainer];
    CGFloat minimumVisibleX = CGRectGetMinX(visibleBounds);
    UIImageView * helpOverlay = [[UIImageView alloc]initWithFrame:CGRectMake(minimumVisibleX, 0, 1024, 768)];
    UIImage * helpImage = [UIImage imageNamed:@"HelpOverLay.png"];
    [helpOverlay setImage:helpImage];
    helpOverlay.tag = 50;
    self.scrollEnabled = NO;
    [self addSubview:helpOverlay]; 
    tap = [[UITapGestureRecognizer alloc] 
                               initWithTarget:self
                               action:@selector(dismissView)];

    [self addGestureRecognizer:tap];  
}

and dismissView to:

for (UIGestureRecognizer *recognizer in self.view.gestureRecognizers) {
    [self removeGestureRecognizer:tap];
}

EDIT: i think nhahtdh's method is a bit more elegant compared to this one.

EDIT2: it seems you have [self addGestureRecognizer:tap] working so i'm asumming this is a subclass of UIView.