是的,我知道。关于NSOperation
世界有很多问题和答案,但我仍然有些疑惑。我试图用两部分问题来解释我的怀疑。他们彼此相关。
在SO帖nsoperationqueue-and-concurrent-vs-non-concurrent中, Darren 写了
“并发”操作本身是并发的;它不需要 NSOperationQueue为它创建一个线程。
但是稍微搜索一下,我发现NSOperation
,即使它被声明为并发(通过覆盖isConcurrent
方法,例如它返回YES
),可以添加到NSOperationQueue
。这是什么意思?如果我将一个并发NSOperation
添加到队列中,那么幕后发生了什么?相反,如果我按原样使用并发操作(不将其添加到队列中)会发生什么?
Apple doc提供的说明很清楚:
...操作队列忽略返回的值 isConcurrent并始终从a调用操作的start方法 单独的线程。 ...一般来说,如果你总是 使用操作队列的操作,没有理由 他们并发。
然后,我真的对在NSOperation
中使用异步模式感兴趣。我找到了 Dave Dribin (concurrent operations)的好教程。我得到了他职位的整体意义。
您无法使用异步模式(例如,使用异步NSURLConnection
请求),因为无法调用委托。当main
完成后,操作将被删除。解决方案是覆盖start
方法来控制操作生命周期......处理运行循环可能会很痛苦。
现在,试图了解他的帖子,我怀疑是否需要在主线程中运行start
方法。
- (void)start
{
if (![NSThread isMainThread])
{
[self performSelectorOnMainThread:@selector(start) withObject:nil waitUntilDone:NO];
return;
}
// other code here...
}
在处理异步API时,我们可以开始异步 在启动时调用主线程并保持运行直到 它结束了。
你能解释一下为什么吗?
提前谢谢。
答案 0 :(得分:11)
在我看来,isConcurrent
的{{1}}属性容易引起混淆。它的确意味着“异步”。也就是说,当调用NSOperation
时,无论操作是否已完成(异步),它是否会快速返回?或者直到操作完成(同步)才返回?
正如Apple的文档所述,当一个操作排队到-start
时,这并不重要,因为队列在工作线程上调用它,无论如何。如果它是同步的,那么该工作线程将专门用于该操作,直到它完成。如果它是异步的,那么NSOperationQueue
将在操作完成之前返回,并且工作线程可以继续进行其他工作。
问题是,异步-start
方法如何确保操作的工作继续进行? 可能需要产生一个单独的线程才能完成工作,但这很愚蠢。最好让-start
处理线程。
更有可能的是,它使用由外部事件驱动的运行循环源。异步模式中的NSOperationQueue
就是那种东西。但是,在这种情况下,它必须确保它调度运行循环源的线程a)将继续存在,并且b)将运行其运行循环。 NSURLConnection
的工作线程不能依赖它们。
同样,你可以为每个这样的操作创建自己的线程,特别是坚持并运行它的运行循环,但这是不必要的,再次,没有优势使得操作保持同步并排队
你已经知道的一个线程会坚持并运行它的运行循环是主线程。因此,通常最好在主线程的运行循环上安排运行循环源。唯一需要注意的是,为了响应触发运行循环源处理程序的外部事件,您不会在主线程上执行任何长时间运行的工作。因此,例如,当NSOperationQueue
使用接收到的数据调用您的委托方法时,您不会对该数据进行昂贵的计算 - 或者,如果必须,则将该昂贵的计算移动到另一个线程。
另一种可能性,即中间立场,就是创建自己的一个线程作为许多异步操作的工作者。因此,不是使用主线程或每个操作的线程,而是使用单个线程,其工作只是停留在其运行循环中。所有异步操作都会在该线程的运行循环上安排自己。但是,这种方法并没有太多需要或优势。
答案 1 :(得分:1)
我认为Dave解决了他将启动方法分流到帖子中主线程的动机:
更新2009-09-13:自10.6起不再适用。启动方法 从10.6开始,总是在后台线程上调用。要正常工作 仅限主线程和依赖运行循环的异步API, 我们需要将我们的工作分流到主线程。更多关于这一点 后续帖子。