Getting "deallocated while key value observers were still registered with it." errors after conversion to ARC

Aaron picture Aaron · Oct 18, 2011 · Viewed 10.3k times · Source

I am using this class:

https://github.com/alexleutgoeb/ALPickerView

Since I converted to ARC, I get this error after clicking on the pickerview a couple of times:

2011-10-18 14:10:19.424 MappingApp[3398:10d03] An instance 0x73c7cd0 of class CustomTapGestureRecognizer was deallocated while key value observers were still registered with it. Observation info was leaked, and may even become mistakenly attached to some other object. Set a breakpoint on NSKVODeallocateBreak to stop here in the debugger. Here's the current observation info: <NSKeyValueObservationInfo 0x5d93430> (<NSKeyValueObservance 0x5d933f0: Observer: 0x5d66eb0, Key path: state, Options: <New: YES, Old: NO, Prior: NO> Context: 0x0, Property: 0x746b180>)

The error points to the CustomTapGestureRecoginizer class and the last line of this method:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesBegan:touches withEvent:event];
    // Simple hack, set recognizer state to possible as tap begins
    self.state = UIGestureRecognizerStatePossible;
}

In checkview, I have this method:

- (void)didMoveToSuperview {
    gestureRec = [[CustomTapGestureRecognizer alloc] initWithTarget:nil action:nil];
    gestureRec.numberOfTapsRequired = 1;
    [gestureRec addObserver:self forKeyPath:@"state" options:NSKeyValueObservingOptionNew context:nil];
    [[self superview] addGestureRecognizer:gestureRec];
}

And, the removeObserver, which I know can cause this problem is in checkview's dealloc. Should I move this somewhere else? Does anyone have any other ideas what might be causing this problem? It never happened before ARC.

Answer

Mattias Wadman picture Mattias Wadman · Oct 18, 2011

I would guess that the method didMoveToSuperview in the CheckView class is called more than once causing the gestureRec instance variable to be reassigned and the previous CustomTapGestureRecognizer instance considered to have no references left by ARC and then be dealloced (causing the warning message that someone is still observing the instance).

Try to add NSLog(@"didMoveToSuperview: self=%@ gestureRec=%@", self, gestureRec); to the beginning of didMoveToSuperview to see if this is the case.

If so a quick fix is probably something like this but I haven't tried it myself or know much about the code.

- (void)didMoveToSuperview {
  if (gestureRec != nil) {
    [gestureRec removeObserver:self forKeyPath:@"state"];
  }
  gestureRec = [[CustomTapGestureRecognizer alloc] initWithTarget:nil action:nil];
  gestureRec.numberOfTapsRequired = 1;
  [gestureRec addObserver:self forKeyPath:@"state" options:NSKeyValueObservingOptionNew context:nil];
  [[self superview] addGestureRecognizer:gestureRec];   
}