87

How do you remove an observer from an object under ARC? Do we just add the observer and forget about removing it? If we no longer manage memory manually where do we resign from observing?

For example, on a view controller:

[self.view addObserver:self
            forKeyPath:@"self.frame"
               options:NSKeyValueObservingOptionNew 
               context:nil];

Previously, I would call removeObserver: in the view controller's dealloc method.

drunknbass
  • 1,662
  • 1
  • 13
  • 19
  • 4
    Note that it's a very bad idea to KVO .frame. As written swhere else by Apple engineers on StackOverflow, UIKit's frame property is not KVO compliant. When it works, it's only by pure chance. – steipete Dec 04 '11 at 13:04
  • 2
    Shouldn't your keyPath be `@"frame"` rather than `@"self.frame"`? – Besi Aug 10 '12 at 20:29

3 Answers3

126

You still can implement -dealloc under ARC, which appears to be the appropriate place to remove the observation of key values. You just don't call [super dealloc] from within this method any more.

If you were overriding -release before, you were doing things the wrong way.

Brad Larson
  • 170,088
  • 45
  • 397
  • 571
  • 1
    Are you sure about this? I quote from http://clang.llvm.org/docs/AutomaticReferenceCounting.html#ownership.spelling.property, section 7.1.2. dealloc: "Rationale: even though ARC destroys instance variables automatically, there are still legitimate reasons to write a dealloc method, such as freeing non-retainable resources. Failing to call [super dealloc] in such a method is nearly always a bug. " – Elise van Looij Nov 28 '11 at 21:42
  • @ElisevanLooij Yes that's true. If you derive from this class, it seems obvious that you must call `[super dealloc]`. Who else should do this for you. – Björn Landmesser Dec 05 '11 at 10:14
  • @ElisevanLooij Oops, well, should have checked before. It is not allowed to call `[super dealloc]` in a dealloc method. No idea how this would work then when subclassing the mentioned class. Maybe it is just advisable to use `finalize` instead (where you call `[super finalize]`) – Björn Landmesser Dec 05 '11 at 10:32
  • 17
    @ElisevanLooij - The point they were trying to make there is in regards to the manual memory management case. Because not calling `[super dealloc]` last in that method is pretty much always a bug under manual memory management, the compiler handles it for you now, which is why you can't call `-dealloc` directly anymore. The only things you put in a `-dealloc` method under ARC are any non-object resources you need to free, or cleanup tasks like removing observers. The wording they use is a little muddy, but this is what they meant. – Brad Larson Dec 05 '11 at 15:13
  • 7
    @BjörnMilcke - As I comment on Elise's answer, `-finalize` is used for this under garbage collection, where `-dealloc` is never called, but it's perfectly acceptable to place this code in `-dealloc` under ARC. `[super dealloc]` is called for you automatically, which is why it's an error to call it under ARC. – Brad Larson Dec 05 '11 at 15:21
1

I do it with this code

- (void)dealloc
{
@try{
    [self.uAvatarImage removeObserver:self forKeyPath:@"image" context:nil];
} @catch(id anException) {
    //do nothing, obviously it wasn't attached because an exception was thrown
}
}    
user3461902
  • 79
  • 1
  • 1
  • 5
  • 2
    What is the point of Exception handling in `dealloc`? It's too late to do anything about it. – Abizern Mar 26 '14 at 02:14
  • What's the point of removing observers on an instance variable in dealloc? This uAvatarImage will be deallocated soon along with any observers it has subscribed to its key paths. – shoumikhin Apr 07 '16 at 06:33
  • 1
    @shoumikhin I'm using ARC and I had to remove the observer in dealloc method. I have the same question you have. However, when I ran multiple instances of the class eventually I got the exc_bad_address error. Doing this resolved the issue. Also, the answer from here http://stackoverflow.com/questions/32490808/com-apple-nsurlsession-work-exc-bad-access-crash-debugging helped me discover the issue. – mac10688 Oct 03 '16 at 19:56
-2

Elsewhere on stack overflow, Chris Hanson advises using the finalize method for this purpose and implementing a separate invalidate method so that owners can tell objects that they are done. In the past I have found Hanson's solutions to be well-thought-out, so I'll be going with that.

Community
  • 1
  • 1
Elise van Looij
  • 4,162
  • 3
  • 29
  • 52
  • 13
    Note that he was referring to garbage collection there, not ARC (his answer was written in 2008). Under garbage collection, `-dealloc` is never called. In ARC, it is. It's perfectly acceptable to remove KVO observers in `-dealloc`, as Chris Lattner (who knows what he's talking about) indicates in Apple's developer forums here: https://devforums.apple.com/message/475850 – Brad Larson Dec 05 '11 at 15:18
  • 3
    Thanks Brad, for doing all this work. No to finalize, yes to dealloc but without [super dealloc]. Simple really, once you know it. Hey, @drunknbass, accept that man's answer! – Elise van Looij Dec 10 '11 at 14:19