【问题标题】:iOS Are methods called by delegates and observers executed on the main thread?iOS 代理和观察者调用的方法是否在主线程上执行?
【发布时间】:2011-10-24 19:20:44
【问题描述】:

抱歉,我不确定这里的语言是否正确,但是当方法被调用时,因为它们要么是委托方法,要么是因为被列为观察者的目标而调用的方法,它们是在主线程上执行的吗?线程?

我想知道我是否可以在这些方法中进行 UI 更改,或者我是否必须将它们包装在

    dispatch_async(dispatch_get_main_queue(), ^{ UI stuff });

TIA:约翰

【问题讨论】:

    标签: ios multithreading


    【解决方案1】:

    对于代表,这可能会有所不同。如果文档没有指定,那么它们通常在主线程上发送。传统上,UIKit 必须在主线程上使用,因此这些委托几乎总是会从主线程中调用。

    对于通知,我想你想要这个小片段。

    通知中心同步向观察者发送通知。换句话说, postNotification: 方法在所有观察者都收到并处理通知之前不会返回。要异步发送通知,请使用 NSNotificationQueue。 在多线程应用程序中,通知总是在发布通知的线程中传递,这可能与观察者自己注册的线程不同

    来自http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/nsnotificationcenter_Class/Reference/Reference.html

    最后,对于 KVO,通知可以来自其他线程。以下是 Apple 工程师对处理它们的看法。

    http://lists.apple.com/archives/cocoa-dev/2007/May/msg00022.html

    【讨论】:

    • 同样对于 NSURLConnection,委托回调在启动异步加载操作的线程上,不一定是主线程。
    • 如果文档清楚地说明这一点肯定会很好,但是例如,UIImagePickerControllerDelegate 协议参考甚至没有使用“线程”这个词。我没有看到 imagePickerController:didFinishPickingMediaWithInfo: 的任何问题,但我突然变得更加意识到线程问题。你的剪辑对我在我的应用程序中使用的通知绝对有帮助。再一次,我的新线程意识让我对它们感到好奇。我将不得不通过它们来确保它们都是正确的。谢谢!
    • 您可以假设对于 UI 对象,委托总是在主线程上。文档将指定是否存在我从未见过的异常​​。您可以从此处的文档中推断出这一点。 developer.apple.com/library/ios/documentation/uikit/reference/…
    • @John 你读过 iOS 版的Thread Programming Guide了吗?
    • 我现在正在再次阅读线程编程指南。 iOS 程序中肯定有很多移动部件。像我这样的新手很难记住所有这些,甚至都知道它们。不过,我快到了。
    【解决方案2】:

    如上所述,线程会因调用者而异。在你的委托方法中,如果你需要适应,你总是可以这样做:

    if ([NSThread isMainThread]) {
        // do the UI stuff as normal
    } else {
        dispatch_async(dispatch_get_main_queue(), ^{ UI stuff });
    }
    

    【讨论】:

    • 如果我不检查当前线程并且总是异步调度会有什么区别?因此,即使在主线程上调用了该委托方法,我也会进行调度,这有什么缺点?或者这个解决方案的优点是什么(检查当前线程)?
    • 我认为即使 dispatch_async 已经在主线程上也不会有任何危害。您必须进行试验以确保 dispatch_async 方法的性能损失不会比检查 NSThread isMainThread 属性差多少。
    【解决方案3】:

    基本思想是,在所有情况下,观察者或委托方法都在同一个线程中调用,初始通知(对于观察者模式)或委托代码正在运行,因此如果您不确定,建议调度您的 UI阻塞在主线程中。我将尝试在下面的推理中证明这些陈述的合理性,当然我可能是错的。

    除非在委托协议文档中明确指定,否则在委托模式中,方法会直接在调用者在调用时运行的同一线程中调用。例如。如果调用者(委托对象)想要调用他的委托并且当前在“Thread-1”上运行,那么调用将发生在同一个线程中:

    
    // this is running in "Thread-1" --> then aDelegateMethod will continue on "Thread-1"
    [myDelegate aDelegateMethod]
    

    就观察者模式而言,我没有看到系统在主线程上显式发送观察通知的任何正当理由,尤其是当发起通知的原始值更改在另一个线程中运行时。事实上,在 KVO 的情况下,运行时通过添加一些覆盖 setter 方法的私有方法来更改类定义以执行通知,并且我看不到在主线程中显式执行此调用的正当理由。因此,据我所知,KVO 通知可以来自任何线程,并且该线程与在观察类中运行值更改的线程相同。

    最后,基于 NSNotificationCenter 的机制看到他的通知是由发布原始通知的同一线程调用的。这在 Apple 文档中有明确说明(值得一提的是,每个线程都有自己的通知队列)。

    因此,在所有情况下,都会维护线程,如果您想确保在主队列中调用您的 UI 块,请使用您在问题中发布的 GCD 调用。

    【讨论】:

    • 再说你最后一句话:这似乎是处理这个问题的最直接的方法。我刚刚浏览了我的代码,并确保我在所有情况下都这样做。我遇到了这个问题,因为我的应用程序在后台线程上创建了一个视频。我想在创建视频时禁用 UI 上的按钮,但这会导致一些松鼠行为。这反过来又让我对线程问题有了新的认识:-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多