3

假设你有一个对象在私有调度队列上做一些内部工作(想想那些不熟悉 GCD 的人的线程)。该对象在其所做的工作中的不同时间通知其委托。从代码当前运行的私有队列中调用委托方法是个坏主意,还是应该在更知名的队列上调用它们?如果是后者,什么队列?似乎主队列可能并不总是您想要的。

选项 A

dispatch_async(private_queue, ^{
    // Do some work...
    [self.delegate tellItWorkWasDone:self];
});

选项 B

dispatch_async(private_queue, ^{
    // Do some work...
    dispatch_sync(dispatch_get_main_queue(), ^{
        [self.delegate tellItWorkWasDone:self];
    });
});

选项 A 的好处是它简单,但缺点是实现委托方法的人将在他们确实不应该在的队列上运行代码。选项 B 可能更安全,但 main_queue 只是一个例子;两者应该如何真正决定他们应该使用什么队列?

谢谢

4

4 回答 4

2

实际上,我建议使用选项 C:为委托回调设置一个专用队列,除非必须在您的课程继续之前完成委托的活动,在这种情况下使用选项 A。

如果 UI 需要更新,delegate 可以自己调度到主队列,不要强制它。

于 2013-04-21T17:04:25.600 回答
1

如果您的代表负责更新 UI,那么您绝对应该使用选项 B,因为Apple 说

重要提示:并非所有 UIKit 类都是线程安全的。在对应用程序主线程以外的线程执行绘图相关操作之前,请务必查看文档。

如果不是这种情况,选项 A 也应该没问题。

于 2013-04-11T05:43:29.293 回答
1

我相信这是您和您的 API 用户之间的合同问题。无论您选择哪种方法,都要明确说明,因为您的 API 的用户必须知道它。

正如@andreagiavatto 正确指出的那样,该决定的意义在于更新 UI 必须在主线程上完成。如果你没有明确说明你的回调完成处理程序是否总是在主线程上排队,你的 API 的用户必须总是采取额外的步骤将它包装在另一个 dispatch_async() 到主线程中,如果它与 UI 相关。

如果您是 API 的唯一用户,那么明确和一致有助于避免愚蠢的错误。

以下是我选择这样做的方式:

  1. 一般规则是我的委托回调与异步运行的代码内联调用,作为您的选项 A
  2. 如果委托回调的目的是提供 UI 反馈的 99%,我将它们排在主线程上,作为您的选项 B,并将其记录在头文件和文档中。
于 2013-04-11T06:59:08.923 回答
1

您还可以在类的 init 中添加一个 delegateQueue 参数。这样,您可以让类的使用者完全控制触发委托调用的队列。

其他答案是正确的,说 UI 操作应该发生在主队列上。但是,如果您的类在消费类不需要时将委托调用排队在主队列上,那将是一种浪费。

于 2014-05-11T11:06:17.853 回答