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
从外观上看,您永远不需要覆盖 isReady
或 isCancelled
,而是根据文档中的说明覆盖 -start
。
【讨论】:
是的,你是对的!我之前一定是误读了文档。我现在在 -start 中启动一个自定义后台线程,我已经删除了 isReady 和 isCancelled 覆盖,现在它可以工作了,完成块只被调用一次:) 我同意您不想实现自己的isReady
或 isCancelled
方法。如果您确实需要自定义isReady
,则必须调用super
:正如文档所说,“如果您想使用自定义条件来确定操作对象的就绪状态,您可以重写此方法并返回一个准确反映的值接收者的就绪状态。如果这样做,您的自定义实现应该调用 super 并将其返回值合并到对象的就绪状态中。您的自定义实现还必须为 isReady 键路径生成适当的 KVO 通知。"以上是关于NSOperation completionBlock 被调用两次的主要内容,如果未能解决你的问题,请参考以下文章