代码之家  ›  专栏  ›  技术社区  ›  zoul

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

  •  19
  • zoul  · 技术社区  · 15 年前

    NSOperation 子类我注意到自动键值观察被 [NSOperation automaticallyNotifiesObserversForKey] 类方法(返回 NO 至少对于某些关键路径)。正因为如此 NSO操作 子类被手动调用到 willChangeValueForKey: didChange… ,在web上的许多代码示例中都可以看到。

    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 一切似乎都很顺利。

    4 回复  |  直到 15 年前
        1
  •  17
  •   Lily Ballard    14 年前

    最可能的解释是kvo键与标准约定不匹配。通常有这样的方法 -isExecuting -setExecuting: ,其中键路径为 @"executing" @"isExecuting" 相反。

    -setIsExecuting: 改变这个值。相反,它们将executing/finished标志基于其他内部状态。在这种情况下,绝对需要使用显式的willChange/didChange通知。例如,如果我有一个NSOperation包装一个nsurl连接,我可能有2个ivar,其中一个名为 data 保存下载数据的 connection 它持有nsurl连接,我可以实现如下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"];
    

    结束。

        2
  •  7
  •   Rob Md Fahim Faez Abir    11 年前

    automaticallyNotifiesObserversForKey 似乎有用,但我个人放弃了 isExecuting isFinished executing finished

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

    然后,我为这两个属性编写自定义设置器,它们执行必要的操作 I执行 完成了吗 通知:

    - (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 需要;以及
    • 我现在可以用 执行 完成

    我必须承认我喜欢凌驾于 自动通知服务器市场


    注意,如果在ios8或Yosemite中执行此操作,还必须在 @implementation :

    @synthesize finished  = _finished;
    @synthesize executing = _executing;
    
        3
  •  0
  •   Chris Forever    8 年前

    [self addObserver:self
           forKeyPath:@"isReady"
              options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial
              context:&ctxKVO_CSDownloadOperation];
    
    [self addObserver:self
           forKeyPath:@"isExecuting"
              options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial
              context:&ctxKVO_CSDownloadOperation];
    
    [self addObserver:self
           forKeyPath:@"isFinished"
              options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial
              context:&ctxKVO_CSDownloadOperation];
    
    [self addObserver:self
           forKeyPath:@"isCancelled"
              options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial
              context:&ctxKVO_CSDownloadOperation];
    
    ...
    
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
    {
        if (context == &ctxKVO_CSDownloadOperation) {
            NSLog(@"KVO: %@", keyPath);
        } else {
            [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
        }
    }
    

    2017-08-02 14:29:58.831 CSDownloader[77366:5089399] isReady : 1
    2017-08-02 14:29:58.831 CSDownloader[77366:5089399] KVO: isReady
    2017-08-02 14:29:58.831 CSDownloader[77366:5089399] isExecuting : 0
    2017-08-02 14:29:58.831 CSDownloader[77366:5089399] KVO: isExecuting
    2017-08-02 14:29:58.831 CSDownloader[77366:5089399] isFinished : 0
    2017-08-02 14:29:58.832 CSDownloader[77366:5089399] KVO: isFinished
    2017-08-02 14:29:58.832 CSDownloader[77366:5089399] isCancelled : 0
    2017-08-02 14:29:58.832 CSDownloader[77366:5089399] KVO: isCancelled
    2017-08-02 14:29:58.832 CSDownloader[77366:5089399] isReady : 1
    2017-08-02 14:29:58.832 CSDownloader[77366:5089399] KVO: isReady
    2017-08-02 14:29:58.833 CSDownloader[77366:5089399] isExecuting : 0
    2017-08-02 14:29:58.833 CSDownloader[77366:5089399] KVO: isExecuting
    2017-08-02 14:29:58.833 CSDownloader[77366:5089399] isFinished : 0
    2017-08-02 14:29:58.833 CSDownloader[77366:5089399] KVO: isFinished
    2017-08-02 14:29:58.833 CSDownloader[77366:5089399] isCancelled : 0
    2017-08-02 14:29:58.833 CSDownloader[77366:5089399] KVO: isCancelled
    2017-08-02 14:29:58.834 CSDownloader[77366:5089399] isReady : 1
    2017-08-02 14:29:58.834 CSDownloader[77366:5089399] KVO: isReady
    2017-08-02 14:29:58.834 CSDownloader[77366:5089399] isExecuting : 0
    

        4
  •  -3
  •   Community Mohan Dere    6 年前

    这个 NSOperationQueue 不是在观察 isFinished isExecuting ,它正在观察 finished executing .

    完成了吗 只是属性的合成get访问器 完成 . 将为此属性发送自动键值观察通知,除非您的子类通过实现 +automaticallyNotifiesObserversForKey +automaticallyNotifiesObserversOf<Key> 如果您没有选择退出自动KVO通知,则不需要使用执行手动通知 will/DidChangeValueForKey: 完成了吗 I执行 ,它们不是

    TL;DR:这些不是NSOperationQueue要寻找的关键路径。

    These are not the key paths you are looking for

    是正确的关键路径,它们应该发送自动KVO通知。

    如果你是 关于KVO,并希望为get accessor键路径发送通知,例如 完成了吗 ,将属性注册为密钥路径的依赖项:

    + (NSSet *) keyPathsForValuesAffectingIsFinished {
        NSSet   *result = [NSSet setWithObject:@"finished"];
        return result;
    }
    
    推荐文章