Re: Get error message about registered observers when Object receives dealloc message
Re: Get error message about registered observers when Object receives dealloc message
- Subject: Re: Get error message about registered observers when Object receives dealloc message
- From: Andreas Grosam <email@hidden>
- Date: Sat, 29 Aug 2009 14:08:39 +0200
On Aug 29, 2009, at 2:29 AM, Graham Cox wrote:
Thank you Graham for your reply.
Hi Andreas,
There is a strong code smell here.
How does your observee know who its observers are?
Actually, it does not. My example code is an oversimplification to
show the actual issue. Often, things are much more complex, and
explainig them may draw people away from the actual problem. ;)
The *Observer* will do this:
- (void) dealloc {
[self.observee removeObserver:self forKeyPath:key];
}
However, in my code the *Observee* will receive the dealloc method
first, which in turn causes all its "child" objects - the Observers -
to receive its dealloc message - which is shown above. Here, the
observee is the "parent" object that owns the child objects.
So, the call path is about this:
[observee release]
[observee dealloc]
[observer release]
[observer dealloc]
[observee removeObserver:observer forKeyPath:key]
Since KVO doesn't normally provide that knowledge to the observee,
you must have arranged this yourself, possibly going considerably
out of your way to do so. Whenever you find yourself having to add
great gobs of code to "supplement" the built-in mechanism, something
should start alarm bells ringing that you are doing it wrong. And I
speak from experience here since when I first experimented with KVO,
I made exactly this mistake too.
A basic principle of KVO is that an observee is, by design, happily
unaware of who's watching it. In consequence, the only object(s)
that are responsible for stopping observing are the observers
themselves - the observee should not attempt to "chuck off" its
observers.
This leads to the question of what to do when an observed object is
deallocated. Your design should have ensured that all observers have
stopped observing by then - if it makes it as far as dealloc and
there are still observers registered (as the error message you're
getting indicates) then it's too late.
As you can see in the call path, I didn't ensure this. dealloc is send
to the observer, before KVO is unregistered. Although, it is
**guaranteed** that all observers will be unregistered in this code.
Just too late. But I'm wondering *why* this is too late.
This is not quite the chicken-and-egg situation it appears.
Typically an observed object is owned by another object, and that
owning object might be an observer. So whenever the owner adds or
removes an object, it would also set up/tear down the KVO
observations. It's hard to give more concrete advice without knowing
more about your design, but the bottom line is - observees cannot
and should not be managing their observers.
Well, the actual object hierarchy is more complex. At the root there
is the "Model". The Model owns a number of other child objects.
The child objects are organized in dictionaries and arrays and in a
tree structure. So, now imagine that any child object may be an
observer to any other child object. From the view point of the model,
the ownership seems to be clear: the model owns the children.
But in order to let a certain child observe a model's property (say a
"model.dictionary.object" key path) (which is just another child) -
the ownership should be circumvented. This requirement is a
contradiction.
Please also read my reply to Roland King's answer. I think I have to
introduce some "shutdown" method, that will be send to each object in
the hierarchy, before the dealloc message is received. This shutdown
message will orderly tear down the object hierarchy - without
deallocating the objects.
Regards
Andreas
--Graham
On 28/08/2009, at 11:56 PM, Andreas Grosam wrote:
I'm using key-value-observing where an instance of class MyObservee
has been registered for KVO with other objects which observe a
value in a key path (e.g.: @"drives.model.port"):
The observee itself unregisters all observers in its dealloc method:
@implementation MyObservee
- (void) dealloc
{
[self removeAllObservers]; // basicly: [self
removeObserver:observer forKeyPath:key];
[super dealloc];
}
The observers are sill alive when the observee receives its dealloc
message.
When the observed instance receives its dealloc message, I'm
getting this error message in the console, before the first line of
code in the dealloc method will be executed (note: BEFORE [super
deallocate] has been invoked):
2009-08-28 14:57:49.753 MyApp[886:20b] An instance 0xd21b60 of
class MyObservee is being deallocated while key value observers are
still registered with it. Observation info is being 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 0xd38e00> (
<NSKeyValueObservance 0xd39880: Observer: 0xd356e0, Key path:
drives.model.port, Options: <New: NO, Old: NO, Prior: NO> Context:
0x16df0, Property: 0xd38990>
...
The class MyObservee does NOT have a sub class - that is, [super
dealloc] will not be called somewhere prematurely.
The base class of MyObservee is NSObject.
Am I doing something wrong here?
Thanks in advance for hints.
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden