为什么NSOperation禁用自动键值观察?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (14)

当使用自定义时NSOperation子类我注意到,自动键值观察被[NSOperation automaticallyNotifiesObserversForKey]类方法(返回NO至少在一些关键的路径上是这样的)。的代码NSOperation子类由手动调用willChangeValueForKey:didChange…,在网络上的许多代码示例中都可以看到。

为什么NSOperation做这个?有了自动KVO支持,人们可以简单地为操作生命周期标志声明属性(isExecuting)并通过访问器触发KVO事件,即:

[self willChangeValueForKey:@"isExecuting"];
executing = NO;
[self didChangeValueForKey:@"isExecuting"];
[self willChangeValueForKey:@"isFinished"];
finished = YES;
[self didChangeValueForKey:@"isFinished"];

...可以用这个代替:

[self setIsExecuting:NO];
[self setIsFinished:YES];

在什么地方有陷阱吗?我刚automaticallyNotifiesObserversForKey返回YES事情似乎很顺利。

提问于
用户回答回答于

最有可能的解释是,kvo键不符合标准约定。通常情况下,有如下方法:-isExecuting-setExecuting:,关键路径是@"executing"...。在NSOperation的情况下,关键路径是@"isExecuting"相反。

另一种可能是,大多数NSOperations实际上没有一个名为-setIsExecuting:来改变这个价值。相反,它们将执行/完成标志基于其他内部状态。在这种情况下,绝对需要使用显式的WillChange/didChange通知。例如,如果我有一个NSOperation包装NSURLConnection,我可能有2个Ivar,一个名为data,它保存下载的数据,其中一个名为connection它包含NSURLConnection,我可以实现如下的getter:

- (BOOL)isExecuting {
    return (connection != nil);
}

- (BOOL)isFinished {
    return (data != nil && connection == nil);
}

现在我的-start方法可以使用

[self willChangeValueForKey:@"isExecuting"];
data = [[NSMutableData alloc] init]; // doesn't affect executing, but is used later
connection = [[NSURLConnection connectionWithRequest:request delegate:self] retain];
[self didChangeValueForKey:@"isExecuting"];

开始执行,并且

[self willChangeValueForKey:@"isExecuting"];
[self willChangeValueForKey:@"isFinished"];
[connection cancel];
[connection release];
connection = nil;
[self didChangeValueForKey:@"isFinished"];
[self didChangeValueForKey:@"isExecuting"];

完成。

用户回答回答于

虽然我同意automaticallyNotifiesObserversForKey看起来很有效,但我个人放弃了isExecutingisFinished属性,而不是定义executingfinished

@property (nonatomic, readwrite, getter = isExecuting) BOOL executing;
@property (nonatomic, readwrite, getter = isFinished)  BOOL finished;

然后,我为这两个属性编写自定义设置程序,这将执行必要的操作。isExecutingisFinished通知:

- (void)setExecuting:(BOOL)executing
{
    [self willChangeValueForKey:@"isExecuting"];
    _executing = executing;
    [self didChangeValueForKey:@"isExecuting"];
}

- (void)setFinished:(BOOL)finished
{
    [self willChangeValueForKey:@"isFinished"];
    _finished = finished;
    [self didChangeValueForKey:@"isFinished"];
}

这就产生了:

  • 更习惯BOOL财产申报;
  • 自定义设置器满足以下奇怪通知:NSOperation规定;及
  • 我现在可以用executingfinished在我的操作实现过程中,设置器,而不是向我的代码乱扔通知。

automaticallyNotifiesObserversForKey但我只是担心意外的后果。

注意,如果在IOS 8或Yosemite中这样做,还必须在@implementation:

@synthesize finished  = _finished;
@synthesize executing = _executing;

扫码关注云+社区