When working with a custom NSOperation
subclass I noticed that the automatic key-value observing is disabled by the [NSOperation automaticallyNotifiesObserversForKey]
class method (which returns NO
at least for some key paths). Because of that the code inside of NSOperation
subclasses is littered by manual calls to willChangeValueForKey:
and didChange…
, as visible in many code samples on the web.
Why does NSOperation
do that? With automatic KVO support people could simply declare properties for the operation lifecycle flags (isExecuting
etc.) and trigger the KVO events through the accessors, ie. the following code:
[self willChangeValueForKey:@"isExecuting"];
executing = NO;
[self didChangeValueForKey:@"isExecuting"];
[self willChangeValueForKey:@"isFinished"];
finished = YES;
[self didChangeValueForKey:@"isFinished"];
…could be replaced by this:
[self setIsExecuting:NO];
[self setIsFinished:YES];
Is there a catch somewhere? I just overrode the automaticallyNotifiesObserversForKey
to return YES
and things seem to work fine.
While I agree that overriding
automaticallyNotifiesObserversForKey
appears to work, but I personally forgo theisExecuting
andisFinished
properties altogether and instead defineexecuting
andfinished
properties, which, as Kevin suggests, is more consistent with modern conventions:I then write custom setters for these two properties, which do the necessary
isExecuting
andisFinished
notifications:This yields:
BOOL
property declaration;NSOperation
requires; andexecuting
andfinished
setters throughout my operation implementation, without littering my code with notifications.I must confess that I like the elegance of overriding
automaticallyNotifiesObserversForKey
, but I just worry about unintended consequences.Note, if doing this in iOS 8 or Yosemite, you will also have to explicitly synthesize these properties in your
@implementation
:I don't know why you are talking about NSOperation can not use automatic KVO. But I just try to verify that, therefore it can use KVO.
The result:
So I am really confused about this question and answers...
The most likely explanation is that the kvo keys don't match the standard conventions. Normally one has methods like
-isExecuting
and-setExecuting:
, where the key path is@"executing"
. In the case of NSOperation, the key path is@"isExecuting"
instead.The other possibility is that most NSOperations don't actually have a method named
-setIsExecuting:
to change that value. Instead, they base the executing/finished flags on other internal state. In this case, one absolutely needs to use the explicit willChange/didChange notifications. For example, if I have an NSOperation that wraps an NSURLConnection, I may have 2 ivars, one nameddata
that holds the downloaded data, and one namedconnection
which holds the NSURLConnection, and I may implement the getters like so:Now my
-start
method can useto start executing, and
to finish.
The
NSOperationQueue
is not observingisFinished
orisExecuting
, it is observingfinished
andexecuting
.isFinished
is simply the the synthesized get accessor for the propertyfinished
. Automatic key-value observing notifications will be sent for this property unless your subclass has specifically opted out of automatic KVO notifications by implementing+automaticallyNotifiesObserversForKey
or+automaticallyNotifiesObserversOf<Key>
to return NO. If you have not opted out of automatic KVO notifications, you do not need to perform manual notifications usingwill/DidChangeValueForKey:
. In your case, you were sending manual notifications forisFinished
andisExecuting
, which are not the key paths thatNSOperationQueue
observes.TL;DR: These aren't the key paths that NSOperationQueue is looking for.
executing
andfinished
are the correct key paths, and they should be sending automatic KVO notifications.If you are truly paranoid about KVO and want to send notifications for the get accessor key paths such as
isFinished
, register your property as a dependency of the key path: