NSOperation completionBlock 被调用两次

Posted

技术标签:

【中文标题】NSOperation completionBlock 被调用两次【英文标题】:NSOperation completionBlock is called twice 【发布时间】:2013-05-04 23:30:44 【问题描述】:

我正在研究一个 NSOperation 子类,我遇到了一个非常奇怪的问题,即完成块被连续调用两次。 KVO 调用看起来不错,但完成块仍然奇怪地被调用了两次。我误解了 NSOperation 吗?文档说当isFinished 变为YES 时调用完成块,并且在我的代码中只发生一次:

- (void)main 
    @autoreleasepool 
        [self willChangeValueForKey:@"isExecuting"];
        [self willChangeValueForKey:@"isReady"];
        executing = YES;
        [self didChangeValueForKey:@"isReady"];
        [self didChangeValueForKey:@"isExecuting"];

        //start the operation
    

然后我像这样简单地设置completionBlock

self.completionBlock = ^
    NSLog(@"Completed");

当它完成时,这个方法被调用(它只被调用一次,我仔细检查过)

- (void)completeOperation 
    [self willChangeValueForKey:@"isExecuting"];
    [self willChangeValueForKey:@"isFinished"];
    executing = NO;
    completed = YES;
    [self didChangeValueForKey:@"isExecuting"];
    [self didChangeValueForKey:@"isFinished"];

但是completionBlock被调用了两次,并在控制台中打印了两次“Completed”。

以下是指示当前状态的方法:

- (BOOL)isReady 
    if (executing || cancelled || completed) 
        return NO;
    
    return YES;

- (BOOL)isCancelled 
    return cancelled;


- (BOOL)isConcurrent 
    return YES;


- (BOOL)isExecuting 
    return executing;


- (BOOL)isFinished 
    return completed;

isCancelled 在我的测试代码中永远不会变成YES,所以这不是它的原因。

我真的不明白为什么会调用 completionBlock 两次。即使从完成块内部将完成块设置为零,它有时也会被调用两次,这甚至更奇怪。

【问题讨论】:

【参考方案1】:

不确定这是否是原因,但根据我的经验,没有必要覆盖只读状态属性。您有责任在主循环中定期检查 isCancelled,如果它设置为退出您正在做的任何事情,但我相信其他状态标志(isReady、isFinished、isExecuting)会自动处理。

如果你去掉状态标志处理,只在-main 中执行你的过程,它会触发多少次?

编辑:假设您正在覆盖这些标志以允许并发,那么您应该通读注释in the docs

从外观上看,您永远不需要覆盖 isReadyisCancelled,而是根据文档中的说明覆盖 -start

【讨论】:

是的,你是对的!我之前一定是误读了文档。我现在在 -start 中启动一个自定义后台线程,我已经删除了 isReady 和 isCancelled 覆盖,现在它可以工作了,完成块只被调用一次:) 我同意您不想实现自己的 isReadyisCancelled 方法。如果您确实需要自定义isReady,则必须调用super:正如文档所说,“如果您想使用自定义条件来确定操作对象的就绪状态,您可以重写此方法并返回一个准确反映的值接收者的就绪状态。如果这样做,您的自定义实现应该调用 super 并将其返回值合并到对象的就绪状态中。您的自定义实现还必须为 isReady 键路径生成适当的 KVO 通知。"

以上是关于NSOperation completionBlock 被调用两次的主要内容,如果未能解决你的问题,请参考以下文章

NSOperation

3.多线程NSOperation

iOS开发之多线程技术——NSOperation篇

ios多线程 -- NSOperation 简介

NSOperation创建队列

iOS开发多线程篇 09 —NSOperation简单介绍