我发布这个问题是因为我在这个主题上看到了很多困惑,因此我花了几个小时调试 NSOperation 子类。
问题是当你执行异步方法时,NSOperation 对你没有多大好处,这些方法在异步回调完成之前实际上是不完整的。
如果 NSOperation 本身是回调委托,由于回调发生在不同的线程上,它甚至可能不足以正确完成操作。
假设您在主线程中,并且您创建了一个 NSOperation 并将其添加到 NSOperationQueue 中,NSOperation 中的代码会触发一个异步调用,该调用回调 AppDelegate 或视图控制器上的某些方法。
您不能阻塞主线程,否则 UI 将被锁定,因此您有两种选择。
1) 创建一个 NSOperation 并将其添加到具有以下签名的 NSOperationQueue 中:
[NSOperationQueue addOperations:@[myOp] waitUntilFinished:?]
祝你好运。异步操作通常需要一个运行循环,因此除非您将 NSOperation 子类化或使用块,否则它不会工作,但如果您必须通过在回调完成时告诉它来“完成”NSOperation,那么即使是块也不会工作。
所以......你使用类似于以下内容的子类 NSOperation 以便回调可以告诉操作何时完成:
//you create an NSOperation subclass it includes a main method that
//keeps the runloop going as follows
//your NSOperation subclass has a BOOL field called "complete"
-(void) main
{
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
//I do some stuff which has async callbacks to the appDelegate or any other class (very common)
while (!complete && [runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);
}
//I also have a setter that the callback method can call on this operation to
//tell the operation that its done,
//so it completes, ends the runLoop and ends the operation
-(void) setComplete {
complete = true;
}
//I override isFinished so that observers can see when Im done
// - since my "complete" field is local to my instance
-(BOOL) isFinished
{
return complete;
}
好的 - 这绝对行不通 - 我们已经解决了这个问题!
2)这种方法的第二个问题是,在 runLoops 必须正确终止的情况下(或者实际上从回调中的外部方法调用中完全终止),可以说上面的方法确实有效(它没有)
当我调用它时,让我们在主线程中假设第二个 Im,除非我希望 UI 锁定一段时间,并且不绘制任何东西,否则我不能在 NSOperationQueue addOperation 方法上说“waitUntilFinished:YES”......
那么如何在不锁定主线程的情况下完成与 waitUntilFinished:YES 相同的行为呢?
由于 Cocoa 中有很多关于 runLoops、NSOperationQueues 和异步行为的问题,我将发布我的解决方案作为对这个问题的回答。
请注意,我只回答我自己的问题,因为我检查了 meta.stackoverflow,他们说这是可以接受和鼓励的,我希望下面的答案可以帮助人们理解为什么他们的 runloops 被锁定在 NSOperations 以及他们如何从外部正确完成 NSOperations回调。(其他线程的回调)