NSBlockOperation和start方法

时间:2012-07-21 04:24:59

标签: iphone objective-c ios

在回顾我的代码时,我一直在看到,在许多地方我一直在假设调用[NSBlockOperationInstance start];将在主线程上启动此操作。我不知道为什么我这么想,但我不应该这么肯定。我检查了文档,但没有找到任何明确提到该块运行的线程。但是,在块的主体中​​断言assert([NSThread isMainThread]);确实每次都使用start,所以我不确定这是不是巧合。任何人都对这将如何运作有更深刻的理解?

我忘了提到正在主线程上调用[op start]。

2 个答案:

答案 0 :(得分:12)

好的,这一切都取决于你调用start()的位置。虽然NSBlockOperation会将块分配给其他线程,但start()是同步的,并且在完成给予NSBlockOperation的所有块之后才会返回。

虽然NSBlockOperation将同时执行它给出的块,但NSBlockOperation本身并不是并发的(即,isConcurrent为false)。因此,根据文档,start()将在调用者的线程中完整地执行start()。

由于调用start()的线程在所有块都已执行之前不会返回,因此让调用线程参与执行并发块的线程池是有意义的。这就是为什么你会在线程中看到一些调用start()的块。

如果您在主线程中看到一个块执行,那么您必须从主线程中调用它。

在相关的说明中,如果您的NSBlockOperation包含单个块,则该块将始终在调用线程中执行。

请记住,如果您希望NSOperation完全并发,则必须在子类中实现适当的功能。

除此之外,您可以将任何NSOperation提供给NSOperationQueue,它将同时执行,因为NSOperation被赋予队列,运行该操作的线程调用start()。

就个人而言,除非我需要使用其功能,否则我认为使用NSBlockOperation优于dispatch_async()没有任何优势。如果您只执行一个块,只需调用

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ });

如果你想利用NSBlockOperation的功能,但你不想等待它们在当前的调用线程中完成,那么这样做仍然有意义......

// Add lots of concurrent blocks
[op addExecutionBlock:^{ /*whatever*/ }];
// Execute the blocks asynchronously
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    [op start];
    // Now do what you want after all the concurrent blocks have completed...
    // Maybe even tell the UI
    dispatch_async(dispatch_get_main_queue(), ^{
        // Update the UI now that all my concurrent blocks have finished.
    });
});

修改 解决你对tc答案的评论...

如果你打电话

op = [NSBlockOperation blockOperationWithBlock:^{assert([NSThread isMainThread])}];
[op start];

来自主线程,然后有一些保证,以及一些高概率。

首先,保证[op start]将在调用线程中运行完成。那是因为NSBlockOperation没有覆盖NSOperation的默认行为,它指定它不是并发操作。

接下来,如果NSBlockOperation只有一个块,那么它很可能会在调用线程中运行。您几乎与第一个块在调用线程中运行的概率相同。

但是,上述“概率”并非保证(仅因为文档没有说明)。我想,有些工程师可能会找到一些理由将该单个块旋转到其中一个并发队列,并让调用线程加入另一个线程中正在执行的操作......但我非常怀疑。

无论如何,也许你的困惑来自于NSBlockOperation的文档说它同时执行块,这样做。但是,操作本身不是并发的,因此初始操作是同步的。它将等待所有块执行,并且它可能(或可能不)在调用线程上执行它们中的一些。

虽然不能保证,但我发现只有一个块的NSBlockOperation除了在调用线程上执行外,不太可能做任何事情。

答案 1 :(得分:2)

docs具体说

  

使用默认优先级将添加到块操作的块调度到适当的工作队列。块本身不应对其执行环境的配置做出任何假设。

我怀疑以下内容会崩溃:

NSBlockOperation * op = [NSBlockOperation blockOperationWithBlock:^{ sleep(1); }];
[op addExecutionBlock:^{assert([NSThread isMainThread]); }];
[op start];

简单地执行块有什么问题?