NSDefaultRunLoopMode与NSRunLoopCommonModes

亲爱的好人们的stackoverflow,

就像上次一样,我现在提出一个我最近偶然发现的问题。 我希望那里有人能够给我一些启示。

每当我尝试在UIScrollViewMPMapView或其他东西下载一个大文件时, MPMapView我触摸iPhone屏幕,下载过程就会暂停。 谢天谢地, Jörn发表了一篇很棒的博客文章,提出了一个替代scheme,使用NSRunLoopCommonModes进行连接。

这让我看看两种模式,NSDefaultRunLoopMode和NSRunLoopCommonModes的细节,但苹果文件不好意思解释,除了说

NSDefaultRunLoopMode

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

NSRunLoopCommonModes

使用此值作为模式添加到运行循环中的对象由所有已声明为“通用”模式集合中成员的运行循环模式进行监视;有关详细信息,请参阅CFRunLoopAddCommonMode的说明。

CFRunLoopAddCommonMode

源,定时器和观察器被注册到一个或多个运行循环模式,并且只在运行循环以这些模式之一运行时才运行。 常用模式是一组运行循环模式,您可以定义一组由这些模式共享的源,定时器和观察器。 例如,可以在每个特定的运行循环模式下注册一个源代码,而不是将其注册到运行循环的公共伪模式中,而是在共同模式集的每个运行循环模式下自动注册。 同样,当模式被添加到一组共同模式时,已经注册到公共伪模式的任何源,定时器或观察者被添加到新添加的共同模式。

任何人都可以用人类语言来解释这两个吗?

运行循环是一种允许系统唤醒睡眠线程以便pipe理asynchronous事件的机制。 通常,当你运行一个线程(除了主线程)之外,还有一个选项可以在运行循环中启动线程。 如果线程运行一些sorting或长时间运行的操作而没有与外部事件和定时器交互,则不需要运行循环,但是如果线程需要响应传入事件,则应该将其附加到运行循环以便当新事件到达时唤醒线程。 这是NSURLConnection生成的线程的情况,因为它们只是在传入事件(从networking)上唤醒。

每个线程可以关联到多个运行循环,或者可以关联到一个特定的运行循环,可以设置为在不同的模式下工作。 “运行循环模式”是操作系统用来确定何时传送某些事件或收集它们以便稍后传送的一些规则的惯例。

通常所有的运行循环都设置为“默认模式”,它build立了pipe理input事件的默认方式。 例如:一旦鼠标拖动(Mac OS)或触摸(在iOS)事件发生,则此运行循环的模式设置为事件跟踪; 这意味着线程不会在新的networking事件中被唤醒,但是当用户input事件终止并且运行循环再次设置为默认模式时,这些事件将被传送; 显然,这是操作系统架构师select用户事件而不是后台事件的select。

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

新模式可以添加到常用模式,但这是一个相当低级的操作。

我想通过添加一些注释来结束:

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

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