4

我正在研究一个 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 两次。即使从完成块内部将完成块设置为零,它有时也会被调用两次,这甚至更奇怪。

4

1 回答 1

4

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

如果您剥离状态标志处理并仅执行您的过程,它会触发多少次-main

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

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

于 2013-05-05T09:48:02.963 回答