问题
Im trying to subclass a NSOperation, and read some sample from, they say: when the task finished, using KVO of NSOperation, to finish the operation, code here:
[self willChangeValueForKey:@"isFinished"];
[self willChangeValueForKey:@"isExecuting"]
finished = YES;
executing = NO;
[self didChangeValueForKey:@"isFinished"];
[self didChangeValueForKey:@"isExecuting"];
then isFinished get called
- (BOOL) isFinished{
return(finished);
}
anyone could explain this to me? why isFinished gets called, will the isFinished finish the operation? as I understanded, do KVO manually need [self didChangeValueForKey:@"isExecuting"]; and I didnt see code like addobserver: and observeValueForKeyPath:
I write
-(void)call
{
[self willChangeValueForKey:@"isVip"];
[self didChangeValueForKey:@"isVip"];
}
-(void)isVip
{
NSLog(@"Im vip");
}
isVip is not called when do [self call];
回答1:
The NSOperationQueue
implementation will observe the "isFinished" property of your operation (using KVO) so it knows when to remove it from the queue. isFinished
is most likely being called by internal Apple code after it has been told of the change to its value.
回答2:
Adding to quellish answer, this is how you would override executing, finished, cancelled.
//.m
@interface MyOperation () //class extension, make these otherwise read-only properties read-write, we must synthesize
@property(atomic, assign, readwrite, getter=isExecuting) BOOL executing;
@property(atomic, assign, readwrite, getter=isFinished) BOOL finished;
@property(atomic, assign, readwrite, getter=isCancelled) BOOL cancelled;
@end
@implementation CoreLocationOperation
@synthesize executing, finished, cancelled;
+ (BOOL)automaticallyNotifiesObserversForKey {
return YES;
}
+ (NSSet *)keyPathsForValuesAffectingIsCancelled {
NSSet *result = [NSSet setWithObject:@"cancelled"];
return result;
}
+ (NSSet *)keyPathsForValuesAffectingIsExecuting {
NSSet *result = [NSSet setWithObject:@"executing"];
return result;
}
+ (NSSet *)keyPathsForValuesAffectingIsFinished {
NSSet *result = [NSSet setWithObject:@"finished"];
return result;
}
- (void)start {
//..
//You can use self.executing = YES; (note we can change executing which would otherwise be read-only because we synthesized our own ivar.
[self setExecuting:YES];
...
}
- (void)cancel {
//..
//super will change the properties executing/finished for us or we can do it manually
[super cancel];
...
}
@end
I think this is clearer than having
[self willChangeValueForKey:_NSURLOperationIsFinished];
[self setIsFinished:YES];
[self didChangeValueForKey:_NSURLOperationIsFinished];
回答3:
First, you should not need to do manual KVO notifications. For an NSOperation
subclass KVO notifications should be sent automatically unless your class has opted out of automatic KVO notifications by implementing +automaticallyNotifiesObserversForKey
or +automaticallyNotifiesObserversOf<Key>
to return NO.
NSOperation
subclasses are not very useful unless they are added to an NSOperationQueue
. When an operation is added to a queue, the queue uses KVO to observe the properties that indicate state changes, such as finished
, executing
, cancelled
, etc. Note that these are not isFinished
, isExecuting
, or isCancelled
- those are the names of the synthesized get accessors for those properties.
In your question you include this code:
[self willChangeValueForKey:@"isFinished"];
[self willChangeValueForKey:@"isExecuting"]
finished = YES;
executing = NO;
[self didChangeValueForKey:@"isFinished"];
[self didChangeValueForKey:@"isExecuting"];
What you're doing here is sending manual KVO notifications for the get accessors, not the properties being observed. Instead, this would accomplish what you seem to be trying to do:
[self setFinished:YES];
[self setExecuting:NO];
Rather than accessing instance variables directly, use the accessor methods. This will correctly send automatic change notifications for these properties.
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:
+ (NSSet *) keyPathsForValuesAffectingIsFinished {
NSSet *result = [NSSet setWithObject:@"finished"];
return result;
}
Registering dependencies is part of KVO compliance.
来源:https://stackoverflow.com/questions/18460750/nsoperation-kvo-isfinished