【问题标题】:NSOperation KVO isFinishedNSOperation KVO isFinished
【发布时间】:2013-08-27 08:37:42
【问题描述】:

我试图继承一个 NSOperation,并从中读取一些示例, 他们说:当任务完成时,使用 NSOperation 的 KVO 来完成操作, 代码在这里:

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

然后 isFinished 被调用

- (BOOL) isFinished{
    return(finished);
}

谁能给我解释一下?为什么 isFinished 被调用,isFinished 会完成操作吗?据我了解,KVO 是否需要手动 [self didChangeValueForKey:@"isExecuting"];而且我没有看到像 addobserver: 和 observeValueForKeyPath: 这样的代码

我写

 -(void)call
{
     [self willChangeValueForKey:@"isVip"];
     [self didChangeValueForKey:@"isVip"];
}

-(void)isVip
{
    NSLog(@"Im vip");
}

do [self call]时不调用isVip;

【问题讨论】:

    标签: ios key-value-observing nsoperation


    【解决方案1】:

    NSOperationQueue 实现将观察您的操作的“isFinished”属性(使用 KVO),因此它知道何时将其从队列中删除。 isFinished 很可能在被告知其值发生变化后被 Apple 内部代码调用。

    【讨论】:

    • 操作的dealloc函数是如何以及何时被调用的?
    • dealloc 将在操作的引用计数达到 0 时被调用,即当没有人拥有对它的引用时。
    • 酷,伙计,我给操作一个观察者,当 isFinished 时,我调用 release 并发生 dealloc。非常感谢,
    • 顺便说一句,你提到 NSOperationQueue 观察 isFinished,而苹果代码调用 isFinished,它是一个链,队列观察操作完成,然后它告诉苹果代码调用 isFinished,如果是,我只需运行op by [op start] 没有队列,isFinished 被正常调用。如果去掉didChangeValueForKey,isFinished没有被调用,op也无法释放
    【解决方案2】:

    除了平息答案之外,这就是您将覆盖执行、完成、取消的方式。

    //.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
    

    我认为这比拥有更清楚

    [self willChangeValueForKey:_NSURLOperationIsFinished];
        [self setIsFinished:YES];
        [self didChangeValueForKey:_NSURLOperationIsFinished];
    

    【讨论】:

      【解决方案3】:

      首先,您不需要手动进行 KVO 通知。对于NSOperation 子类,应自动发送 KVO 通知,除非您的类通过实现 +automaticallyNotifiesObserversForKey+automaticallyNotifiesObserversOf<Key> 来返回 NO 选择退出自动 KVO 通知。

      NSOperation 子类不是很有用,除非它们被添加到NSOperationQueue。当一个操作加入队列时,队列使用KVO观察表示状态变化的属性,如finishedexecutingcancelled等。注意这些不是isFinishedisExecuting , 或 isCancelled - 这些是这些属性的综合 get 访问器的名称。

      在您的问题中包含以下代码:

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

      您在这里所做的是为 get 访问器发送手动 KVO 通知,而不是正在观察的属性。相反,这将完成您似乎正在尝试做的事情:

      [self setFinished:YES];
      [self setExecuting:NO];
      

      不要直接访问实例变量,而是使用访问器方法。这将正确发送这些属性的自动更改通知。

      如果您对 KVO真正偏执,并且想要发送获取访问器密钥路径(例如 isFinished)的通知,请将您的属性注册为密钥路径的依赖项:

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

      Registering dependencies is part of KVO compliance.

      【讨论】:

      • 这是不正确的。我会将我们在stackoverflow.com/a/25953779/1271826 的cmets 中的讨论推荐给读者。
      • 作者手动调用KVO通知方法的原始方法是尝试管理关键路径之间的依赖关系。 KVO 有这样做的机制,应该作为第一选择。
      • 很好地添加了关键路径依赖模式以获得所需的isFinished(和其他)通知。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-06
      • 2015-05-26
      相关资源
      最近更新 更多