Removing an Observer
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 r开发者_如何学GoemoveObserver:forKeyPath:
is not a Class Method.
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.
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.
How about sending your object the removeObserver:forKeyPath
message just before you delete it from the ManagedObjectContext
?
From iOS 11 and above, we have automatic registration of KVO. From the Foundation Release Notes for macOS 10.13 and iOS 11
Relaxed Key-Value Observing Unregistration Requirements Prior to 10.13, KVO would throw an exception if any observers were still registered after an autonotifying object's -dealloc finished running. Additionally, if all observers were removed, but some were removed from another thread during dealloc, the exception would incorrectly still be thrown. This requirement has been relaxed in 10.13, subject to two conditions:
• The object must be using KVO autonotifying, rather than manually calling -will and -didChangeValueForKey: (i.e. it should not return NO from +automaticallyNotifiesObserversForKey:) • The object must not override the (private) accessors for internal KVO state
If all of these are true, any remaining observers after -dealloc returns will be cleaned up by KVO; this is also somewhat more efficient than repeatedly calling -removeObserver methods.
精彩评论