views:

203

answers:

3

In a NSManagedObject Sub Class I have the code …

- (void) awakeFromInsert { 
[self addObserver:[NSApp delegate] forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil]; 
}

Which adds my App Delegate as an Observer, what I want to do now is from inside my App Delegate, I want to remove itself as an Observer for my NSManagedObject Sub Class.

How would I do this? Thanks.

I was thinking of adding this to my App Delegate

[JGManagedObject removeObserver:self forKeyPath:@"name"];

but unfortunately removeObserver:forKeyPath: is not a Class Method.

+1  A: 

Much the same way you added the observer in the first place, only with fewer options:

// Given some managed object "object"...
[object removeObserver:self forKeyPath:@"name"];

Note that we remove self as the observer, rather than the application delegate as given by [NSApp delegate], since the code will be running within the delegate itself.

Tim
But the Observer isn't observing the App Delegate it's observing the Managed Object Sub Class.
Joshua
Tim - this is wrong; this would remove observations of the delegate for "name" changes on the delegate -- which were never being observed in the first place (delegate.name). You have to remove observation of the managed object itself.
Jason Coco
Joshua: So change the code to do what you want?
Peter Hosey
So do I replace `object` with `JGManagedObject`(My NSManagedObject Subclass)? I don't think I would because JGManagedObject is a Class.
Joshua
No - this method relies on your app delegate having an *instance* of `JGManagedObject`. So you would somehow need to have an object declared as `JGManagedObject *object = ...` before that line of code is valid.
Tim
But there really isn't anything to put after the `=` is there? Could you not in the Header file just add `JGManagedObject *object`?
Joshua
If you do that, then add the appropriate `@property` and `@synthesize` directives, then set the property to the appropriate object (something like `[[NSApp delegate] setObject:self]` from the JGManagedObject where you register the observer), then yes, you won't need that first line, and can just remove the observer as listed in my answer.
Tim
Ok. So I would also add `@property (nonatomic, retain) JGManagedObject *object;` and `@synthesize object`. However when I do this I get an error, http://grab.by/9Jq.
Joshua
Make sure your NSApp delegate knows that `JGManagedObject` is a class - either `#import` the `JGManagedObject.h` header to the delegate's header, or add a `@class` declaration to the delegate header and import the managed object header in the delegate's implementation file.
Tim
Ok. I've done that, so this is what it looks like now … http://grab.by/9KG http://grab.by/9KF http://grab.by/9KE but I still get an error http://grab.by/9KJ.
Joshua
Joshua - the @synthesize directive goes in the implementation file. And anyway, this isn't going to work for you because you're not watching one object, but lots of them.
Abizern
What do you mean that I'm not watching one object but lots of them?
Joshua
If I make the (not unrealistic) assumption that this question is based on the trouble you are having here http://stackoverflow.com/questions/1548291 then it's plain to see that you are not watching a single object but lots of objects of class JGManagedObject. You're trying to add a property, object, but what is this going to represent?
Abizern
Object is supposed to represent the JGManagedObject class. Basically I should be Key Value Observing the CD 'name' property of all the objects in my Tree Controller, so that when the 'name' property of one of my objects changed it triggers an action.
Joshua
+2  A: 

For something like this, it's probably best to rethink the design. The delegate, in this case, would have to have some specific knowledge of the managed object itself in order to do this -- and the delegate would have to have some idea about when in the lifecycle it should (or would want to) stop observing the object.

You have a few choices. Instead of doing this in awake from insert, you could have the delegate start observing it when it creates it and then stop observing it when it gives up ownership. If that is not feasible in your design, you could have the object remove its observer when it is deallocated. If this is a fire-and-forget (basically the delegate only cares once), you could remove the observer after the first change notification. Since, however, you created the observation within the creation lifecycle of this object, it is probably best to remove that observation at the destruction of the object:

- (void)dealloc
{
  [self removeObserver:[NSApp delegate] forKeyPath:@"name"];
  // other clean-up
  [super dealloc];
}

You might also want to do this when the object awakes from fetch and from fault and release the observer when the object will become a fault.

Jason Coco
Removing the observer in `-dealloc` won't work for Garbage Collected apps, though.
Abizern
And also it's not fire-and-forget, the delegate needs to do it more than once.
Joshua
Yeah, it will work if you're not using GC -- good catch Abizem. If you are using GC then I suggest reworking this so that the delegate registers itself as the observer when it inserts or fetches the objects and then removes itself when it is finished with the object.
Jason Coco
You could also just add it to your finalize method instead of your dealloc method if you are using GC
Jason Coco
Basically I have an IBAction in my App Delegate and when it starts I want to remove the App Delegate as an observer and at the end I want to add the App Delegate as an observer of The NSManagedObject sub class again. Does this help you understand my situation?
Joshua
Ah, so just do that. In beginning of your method send the object the remove observer message: [obj removeObserver:[NSApp delegate] forKeyPath:@"name"]; then just add it again at the end of your method: [obj addObserver:[NSApp delegate] forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];
Jason Coco
A: 

How about sending your object the removeObserver:forKeyPath message just before you delete it from the ManagedObjectContext?

Abizern