Take the 2-minute tour ×

I have a view (we'll call this view A) that has a weak property to its superview (view B). View A KVO's its superview, view B. Since view A's reference to view B is a weak property (to prevent a retain cycle), how can I remove the observer (A observing B)? View A's reference to view B gets nil'd out before I have a chance to remove it.

A outlives B since the view controller has a strong reference to A. Here's the leaking log message:

<NSKeyValueObservationInfo 0x8660360> (
<NSKeyValueObservance 0x8660320: Observer: 0x8660020, Key path: contentOffset, Options: <New: YES, Old: NO, Prior: NO> Context: 0x8660020, Property: 0x864ac80>

B is a UITableView. Setting a breakpoint at NSKVODeallocateBreak yields useless results.

In A's removeFromSuperview, I try to remove the observer but A's reference to B is already nil.

Switching to unsafe_unretained and do things more manually or calling [A removeFromSuperview] in the view controller's dealloc solves the problem. I'd like to know how to solve this using a weak property though.

Here's the relevant code: https://gist.github.com/2822776

share|improve this question
My bad... +1 anyhow. –  CodaFi May 29 '12 at 4:59
Related issue on GitHub I'm hoping to solve with the answer. –  Sam Soffes May 29 '12 at 6:26
add comment

3 Answers

I find any kind of code required specially for this case really unnecessary as removal can be automated.

With the introduction of ARC, Apple should have provide automatic removal of observers that would fix cases like this, but unfortunately they didn't. But I've made my own category that adds this lacking feature: https://github.com/krzysztofzablocki/SFObservers I've explained how I did manage that on my blog: http://www.merowing.info/2012/03/automatic-removal-of-nsnotificationcenter-or-kvo-observers/

If you look at my solution you will notice, that it makes sure that original code is called, even if one of the methods call other ones, so that even if apple changes its internal behavior the category will still work fine :)

share|improve this answer
Your SFOvservers looks cool. I was hoping to use a less clever solution. Swizzling stuff on NSObject is a bit scary. Who knows what they'll change in iOS 6. –  Sam Soffes May 29 '12 at 16:22
That's why my solution doesn't assume any order of original methods and instead calls the original code :-) So that is future proof if they change anything. –  Krzysztof Zabłocki May 29 '12 at 17:14
add comment

You could define an explicit weak property referencing the superview and then observe self with a key path like @"propertyReferringSuperview.propertyOfSuperview"? When you get a KVO notification, you check if self.propertyReferringSuperview == nil and stop observing @"propertyReferringSuperview.propertyOfSuperview".

share|improve this answer
I've tried this approach. When the weak reference to the superview gets niled out, KVO doesn't fire. –  Sam Soffes May 29 '12 at 16:23
What a shame… Maybe try to insert cleanup into the custom setter setPropertyReferringSuperview:? I hope it gets called when the weak reference becomes nil. Actually, you can start and stop observing right in this setter. –  Stream May 29 '12 at 21:50
add comment

Instead of adding a weak property, you could just use the superview property and implement willMoveToSuperview: to add/remove the KVO observation.

- (void)willMoveToSuperview:(UIView *)newSuperview {
    [self.superview removeObserver:self forKeyPath:@"contentOffset" context:context];
    [newSuperview addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:context];
    [super willMoveToSuperview:newSuperview]; // optional as default implementation does nothing
share|improve this answer
When willMoveToSuperview: is called, the weak property referencing view B (or scrollView in the Gist) is already nil. –  Sam Soffes May 29 '12 at 16:20
Yes but you told that view B is A's superview. So you have no need for the scrollView property. Just use superview. –  Nicolas Bachschmidt May 30 '12 at 8:50
add comment

Your Answer


