Re: KVO can be unsafe in -init?
Re: KVO can be unsafe in -init?
- Subject: Re: KVO can be unsafe in -init?
- From: Roland King <email@hidden>
- Date: Wed, 09 Sep 2009 11:03:24 +0800
John Chang wrote:
Hi all,
Question: is it unsafe for some reason to be adding yourself as a KVO
observer during -init?
We have a singleton with an -init that looks something like this:
- (id)init
{
if ((self = [super init]))
{
_foo = [[NSMutableDictionary alloc] init];
_bar = [[NSMutableDictionary alloc] init];
[[XYZManager sharedManager] addObserver:self forKeyPath:@"allObjects"
options:NSKeyValueObservingOptionInitial context:NULL];
}
return self;
}
This code is running on iPhone OS. On some devices (we haven't been to
narrow this down), the last line of code is throwing an exception:
Sun Sep 6 13:41:26 unknown MyApp[1609] <Error>: *** Terminating app due to
uncaught exception 'NSInvalidArgumentException', reason: '***
-[NSCFDictionary setObject:forKey:]: attempt to insert nil key'
We know that [XYZManager sharedManager] can't be nil, since otherwise
-addObserver: would not be getting called, and the first line "if ((self =
[super init]))" ensures that self can't be nil. We're pretty sure
that [XYZManager sharedManager].allObjects is not nil, but even if it were
nil, that shouldn't cause an exception. -allObjects is a synthesized getter
with no dependent keys. No other threads are involved here.
So we're stumped as to why KVO is throwing an exception. The only theory is
that the NSKeyValueObservingOptionInitial option is causing KVO to do
something with self immediately, but self isn't fully "set up" yet. Though
it's unclear why in this particular usage that would be unsafe, or why it
would make any difference. Can anyone provide any insight?
I don't see anything wrong with what you're attempting to do, as long as
you're a little careful.
Your NSKeyValueObservingOptionInitial isn't being magically intercepted,
I'm quite sure. However that will cause your KVO handler to be executed
immediately to give you the initial value, before the registration
method returns, are you fully set-up to receive it at that point, is it
really the last line before you return self? What happens if your class
has been subclassed and that subclass has its own
observeValueForKeyPath:ofObject:change:context: method, I'm not entirely
sure which one would be called, but I think it would be your subclasses,
and your subclass initializer hasn't yet been called.
One thing to note, you're using a context of NULL, which I used to do
all the time until I got badly bitten. Don't do that, set a context for
your observations and check it, the pattern is in the documentation and
XCode will even generate a stub for it. You must check the context, you
must call the superclass implementation. That would save you by the way
in the case you have been subclassed and the subclass method has been
called as the contexts wouldn't match and the subclass would pass the
observation back up to you.
_______________________________________________
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