Reputation: 11
According to Apple and numerous examples I've seen, there is no problem using KVO/KVC to observer yourself. Also according to those same sources, it's not a problem setting this up by using addObserver:forKeypath:options:context: in an object's init method, a la:
- (id)init
{
self = [super init];
if (self) {
[self addObserver:self
forKeyPath:@"selected"
options:NSKeyValueObservingOptionNew
context:NULL];
}
return self;
}
Unfortunately for some reason, my observer method does not get called when I do it there. If I move the addObserver call to another method and then invoke that method in the calling method:
MyObject *newObj = [[MyObject alloc] init];
[newObj setupObservers];
Then all is fine. This is a subclass of NSImageView, so it's not like there's any 'awakeFromNib'-type alternative here... I'm really scratching my head here and I'm sure I'm missing something obvious - like a rule about things which will cause KVO on self to not work in init methods, but I haven't found anything in the docs which would give me any hints here.
What do I not know?
Upvotes: 1
Views: 4804
Reputation: 106
Basically you are trying to add a KVO notifications to an object that is not yet initialized (your init function add the observer before you return the self). Move the following code:
[self addObserver:self
forKeyPath:@"selected"
options:NSKeyValueObservingOptionNew
context:NULL];
into the - (void)viewDidLoad
instead. It's gonna be fine.
Upvotes: 0
Reputation: 280
As for the context pointer, the preferred way is:
static void *MyPrivateObservationContext = (void*)@"MyPrivateObservationContext"; // we assume MyPrivateObservationContext is a unique name, I use something of the form ClassNamePropertyObservationContext
then
-[obj add....... context:&MyPrivateObservationContext];
Then in
-(void)observeValueForKeyPath:....context:c;
{
if (c == &MyPrivateObservationContext) {
// do work
} else {
[super observeValueForKeyPath:...];
}
}
Upvotes: 2
Reputation: 456
The problem is probably that -init is not invoked in your case, -initWithCoder: is.
Every Cocoa class has a set of init methods called its "designated initializers". Each object, as its being instantiated, is guaranteed to go through one and only one of the designated initializers of each class in its inheritance tree.
If you're subclassing a class and have initialization to do, you must override all of the designated initializers of the superclass.
The designed initializers of NSImageView are -initWithCoder: and initWithFrame:. Override those two, not init.
Upvotes: 4
Reputation: 299455
This is a subclass of NSImageView, so it's not like there's any 'awakeFromNib'-type alternative here...
I don't understand this point. Are you creating this object in a NIB or not? If a NIB is creating this object, then it will call -awakeFromNib
. The first thing you should establish (using NSLog()
) is whether your -init
is actually running. When nothing happens, it usually means code did not run.
Upvotes: 0
Reputation: 6409
I'm not sure whether there is such restriction or not, but even if you don't have a awakeFromNib
you can create one by adding setupObservers
to the run-loop in your init method:
[[NSRunLoop currentRunLoop]
performSelector:@selector(setupObservers)
target:self
argument:nil
order:1
modes:NSDefaultRunLoopMode];
Upvotes: 0