【问题标题】:GCD vs performSelectorInBackground/performSelectorOnMainThreadGCD 与 performSelectorInBackground/performSelectorOnMainThread
【发布时间】:2013-10-21 17:18:42
【问题描述】:

我是 ios 开发的新手。我有以下问题:

  1. 当我们使用 GCD(dispatch_group_async, dispatch_async(dispatch_get_main_queue()...) 以及当我们使用 performSelectorInBackground/performSelectorOnMainThread 时?
  2. 这两者有什么区别。

    我知道当我们使用 performSelectorInBackground 时,我们会创建一个新的 NSThread。但是当我们使用dispatch_group_async时不一样吗?因为如果我们创建了多个dispatch_group_async,这意味着我们需要在队列中提交多个blocks。这些块可能在不同的队列上运行。所以,当我们创建多个dispatch_group_async的时候,是不是就意味着我们创建了一个新线程呢? (因为块可能在不同的队列上运行)(我对 NSThread 和块队列有点困惑.....)

谢谢!!

【问题讨论】:

    标签: ios objective-c nsthread


    【解决方案1】:

    何时使用performSelectorInBackground:

    从来没有。不要使用这种方法。它产生无限数量的线程。甚至在 GCD 可用之前,这就是一种可怕的方法。

    何时使用performSelectorOnMainThread:

    嗯……从来没有,只是因为它不方便。这种方法没有什么严重的错误。它只是没有dispatch_async() 有用。

    GCD 与旧的performSelector… 方法(以及一般的NSThread)之间的区别在于GCD 为您管理一个线程池。一般来说,你应该避免在 Cocoa 中手动线程。相反,请使用NSOperationQueue 或 GCD(dispatch 方法)。它们提供了更有用的队列抽象,而不是强迫您手动管理线程。

    请务必阅读 Apple 的 Migrating Away from Threads 以了解更多信息。

    【讨论】:

    • dispatch_[a]sync 到主队列并不像您想象的那样等效。它将您的代码与不可重入服务的主运行循环联系起来。有很多(相对模糊,公平地说)调度会产生与 CFRunLoopPerformBlock 或 performSelectorOnMainThread 不同的结果。
    • @Catfish_Man,我同意存在一些细微的差异,尤其是在 Mac 上。当 NSAttributedString 转换 HTML 时,它会抽出 runloop,如果您已经在主 runloop 上安排了其他事情,这可能会导致死锁。并且总是存在运行循环模式和滚动的棘手情况。所有这些都指向您使用 GCD 或操作队列 IMO,因此建议不会改变。仅仅为了方便主要是避免使用 performSelectonOnMainThread: 的原因,您可以将 runloop 中一些晦涩的极端情况视为“不方便”的子集。
    • 是的,我并不是真的试图指向或远离特定的 API。只是提醒一下,它们并不是严格意义上的替代品。
    • 我应该使用dispatch_async() 来简单地使用showUIAlertView[NSURLSession sharedSession].delegateQueue 吗? Brian Coleman says to use performSelectorOnMainThread:withObject:waitUntilDone: to update the UI from a background thread.
    • 我也会用dispatch_async 做那个。然后您可以将所有UI* 方法移动到主线程。并且更容易看到 dispatch_async 中发生的事情(show 没有隐藏在选择器中)。虽然init 在后台可能是安全的,但最好将所有 UIKit 内容移至主线程,除非您有充分的理由不这样做。然后你不必研究每个 UIKit 调用来仔细检查。顺便说一句,“似乎工作”对线程安全毫无意义。高度不安全的代码可以正确运行数千次,但仍然会在现场崩溃。
    【解决方案2】:

    实际上,在 iOS 4.0 之后,我找不到使用 performSelectorInBackground/onMainThread 的任何单一理由。如果您需要在后台执行某些操作,请使用 GCD(或者更好的是 NSOperationQueue,它自 4.0 以来构建在 GCD 之上,并提供更大的灵活性且开销很小),但请确保在使用块时不要创建保留循环。

    【讨论】:

    • dispatch_[a]sync 到主队列并不像您想象的那样等效。它将您的代码与不可重入服务的主运行循环联系起来。有很多(相对模糊,公平地说)调度会产生与 CFRunLoopPerformBlock 或 performSelectorOnMainThread 不同的结果。
    • @Catfish_Man,如果想了解更多关于这些情况的信息会很有趣。
    • @Catfish_Man 您能否详细说明,或链接到相关问题和/或来源?谢谢
    • 这里间接提到了一个问题:developer.apple.com/library/mac/documentation/Darwin/Reference/…,它说“提交到主队列的块将作为应用程序主 NSRunLoop 或 CFRunLoop 的“常见模式”的一部分执行”。所以如果你的runloop不是在普通模式下运行,那么主队列上的块就不会执行。
    • 对于另一个问题,CFRunLoop 文档中的这一点暗示了这一点:“运行循环可以递归运行。您可以在任何运行循环标注中调用 CFRunLoopRun 或 CFRunLoopRunInMode 并创建嵌套的运行循环激活当前线程的调用堆栈。您可以在调用中运行的模式不受限制。您可以创建在任何可用的运行循环模式下运行的另一个运行循环激活,包括已经在调用堆栈中运行更高的任何模式。调度队列不是这样,包括主队列。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-23
    • 1970-01-01
    • 2011-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多