NSDefaultRunLoopMode与NSRunLoopCommonModes


114

每当我尝试下载一个大文件的背后UIScrollViewMPMapView或者什么的,下载过程被当我触摸iPhone屏幕停止。值得庆幸的是,Jörn的一篇很棒的博客文章提出了一种替代方法,NSRunLoopCommonModes用于连接。

这让我详细了解了两种模式,即NSDefaultRunLoopMode和NSRunLoopCommonModes,但是苹果文档并没有详细说明,除了说

NSDefaultRunLoopMode

处理NSConnection对象以外的输入源的模式。这是最常用的运行循环模式。

NSRunLoopCommonModes

使用此值作为模式添加到运行循环的对象由已声明为“公共”模式集的成员的所有运行循环模式监视;有关详细信息,请参见CFRunLoopAddCommonMode的描述。

CFRunLoopAddCommonMode

源,计时器和观察者被注册到一个或多个运行循环模式,并且仅在运行循环以其中一种模式运行时运行。通用模式是一组运行循环模式,您可以为其定义一组由这些模式共享的源,计时器和观察器。例如,您无需将源注册到每个特定的运行循环模式,而只需将其注册到运行循环的公共伪模式一次,它将在公共模式集中的每个运行循环模式下自动注册。同样,当将一种模式添加到一组公共模式时,任何已注册到该公共伪模式的源,计时器或观察者都将添加到新添加的公共模式中。

谁能用人类语言解释两者吗?

Answers:


204

运行循环是一种机制,允许系统唤醒睡眠线程,以便它们可以管理异步事件。通常,当您运行线程(主线程除外)时,可以选择是否在运行循环中启动线程。如果线程运行某种排序或长时间运行的操作而没有与外部事件交互且没有计时器,则不需要运行循环,但是如果您的线程需要响应传入的事件,则应将其附加到运行循环中,以便新事件到来时唤醒线程。NSURLConnection生成线程就是这种情况,因为它们仅在传入事件(从网络)中唤醒时才唤醒。

每个线程可以与多个运行循环关联,也可以与可以设置为在不同模式下工作的特定运行循环关联。“运行循环模式”是操作系统使用的约定,用于为何时传递某些事件或收集事件以供稍后传递建立一些规则。

通常,所有运行循环都设置为“默认模式”,这建立了管理输入事件的默认方式。例如:鼠标事件(Mac OS)或触摸事件(iOS上)发生时,此运行循环的模式将设置为事件跟踪;这意味着线程不会在新的网络事件上被唤醒,但是这些事件将在以后用户输入事件终止并且运行循环再次设置为默认模式时传递。显然,这是OS架构师做出的选择,即优先考虑用户事件而不是后台事件。

如果您决定NSURLConnection通过使用来更改线程的运行循环模式scheduleInRunLoop:forModes:,则可以将线程分配给特殊的运行循环模式,而不是特定的默认运行循环。NSRunLoopCommonModes包括事件跟踪在内的许多输入源都使用称为的特殊伪模式。例如,将NSURLConnection实例分配给共模意味着将其事件与“默认模式”关联到“跟踪模式”。NSRunLoopCommonModes将线程与之关联的一个优点/缺点是线程不会被触摸事件阻塞。

可以将新模式添加到通用模式,但这是一个很底层的操作。

最后,我想补充一些注意事项:

  • 通常,我们需要使用从网络下载的带有表视图的一组图像或缩略图。我们可能认为在表格视图滚动时从网络上下载这些图像可以改善用户体验(因为在滚动时我们可以看到图像),但这不是有利的,因为滚动的流动性会受到很大的影响。在此示例中,NSURLConnection不应使用运行循环。最好使用UIScrollView委托方法来检测滚动何时终止,然后更新表并从网络下载新项目。

  • 您可以考虑使用GCD,这将帮助您“屏蔽”运行循环管理问题中的代码。在上面的示例中,您可以考虑将网络请求添加到自定义串行队列中。


9
尊敬的Viggio24,非常感谢您提供干净,准确的说明。我要求苹果将您的评论添加到他们的API指南中。;)
Stkim1 2011年

7
viggio24的答案是完美的。对于那些感兴趣的人,我会指出WWDC 2010的Session 208(iPhone OS的网络应用程序,第2部分)包含运行循环的简介。如果您有兴趣,请看一看。希望能帮助到你。
Lorenzo B

19
给自己一个提示:NSRunLoopCommonModes滚动时允许定时器事件UIScrollViewNSDefaultRunLoopMode滚动时防止定时器。
2013年

2
我发现有关滚动视图更新的评论非常有趣,因为它提到了一个非常具有挑战性的主题。只是要添加更多详细信息:在为NSURLConnection设置模式时,这只会影响委托回调的执行。我了解更新此处的scrollView可能会导致性能问题,但是为什么会发生这种情况?如果答案是必须将图片加载到内存中,则可以通过在后台写入图形上下文来实现,然后在执行此操作后更新视图主线程层。听起来合理吗?
nebillo 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.