【发布时间】:2012-08-30 09:24:48
【问题描述】:
我发布这个问题是因为我看到很多关于这个主题的困惑,因此我花了几个小时调试 NSOperation 子类。
问题在于,当您执行异步方法时,NSOperation 对您没有多大好处,而这些方法在异步回调完成之前实际上是不完整的。
如果 NSOperation 本身是回调委托,由于回调发生在不同的线程上,它甚至可能不足以正确完成操作。
假设您在主线程中并创建一个 NSOperation 并将其添加到 NSOperationQueue 中,NSOperation 中的代码会触发异步调用,该调用回调 AppDelegate 或视图控制器上的某些方法。
你不能阻塞主线程,否则 UI 会被锁定,所以你有两个选择。
1) 创建一个 NSOperation 并将其添加到具有以下签名的 NSOperationQueue 中:
[NSOperationQueue addOperations:@[myOp] waitUntilFinished:?]
祝你好运。异步操作通常需要一个 runloop,因此除非你继承 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 必须正确终止(或实际上从外部终止回调中的方法调用)
当我调用它时,让我在主线程中假设一秒钟,除非我希望 UI 锁定一段时间,并且不绘制任何东西,否则我不能在 NSOperationQueue addOperation 方法上说“waitUntilFinished:YES”。 .
那么如何在不锁定主线程的情况下完成与 waitUntilFinished:YES 相同的行为呢?
由于 Cocoa 中有很多关于 runLoops、NSOperationQueues 和异步行为的问题,我将发布我的解决方案作为对这个问题的回答。
请注意,我只回答我自己的问题,因为我检查了 meta.stackoverflow,他们说这是可以接受和鼓励的,我希望 接下来的答案可以帮助人们理解为什么他们的 runloops 被锁定NSOperations 以及它们如何从外部回调中正确完成 NSOperations。 (其他线程的回调)
【问题讨论】:
-
鼓励回答您自己的问题,但您应该首先将问题作为问题提出,然后使用标准 SO 回答系统回答。你刚刚写的是一篇博文。
-
我刚刚做了,我想确保问题很清楚,没有在问题中给出答案...答案如下
标签: objective-c ios objective-c-blocks objective-c-runtime