亲爱的stackoverflow人,
就像上次一样,我特此提出一个我最近偶然发现的问题。我希望有人可以对我有所了解。
每当我尝试下载UIScrollView
,MPMapView
之后的大文件时,只要我触摸iPhone屏幕,下载过程就会停止。值得庆幸的是,Jörn的一篇精彩博客文章提出了另一种选择,使用NSRunLoopCommonModes
进行连接。
这让我看看两种模式的细节,NSDefaultRunLoopMode和NSRunLoopCommonModes,但苹果文档并没有好好解释,除了说
NSDefaultRunLoopMode
处理NSConnection对象以外的输入源的模式。 这是最常用的运行循环模式。
NSRunLoopCommonModes
使用此值作为模式添加到运行循环的对象由已声明为“常用”模式集的成员的所有运行循环模式监视;有关详细信息,请参阅CFRunLoopAddCommonMode的说明。
CFRunLoopAddCommonMode
源,定时器和观察器被注册到一个或多个运行循环模式,并且仅在运行循环以其中一种模式运行时运行。常用模式是一组运行循环模式,您可以为其定义这些模式共享的一组源,定时器和观察器。例如,不是将源注册到每个特定的运行循环模式,而是可以将其注册到运行循环的公共伪模式,并且它将在共模模式集中的每个运行循环模式中自动注册。同样,当一个模式被添加到一组共同模式时,已经注册到公共伪模式的任何源,定时器或观察者都被添加到新添加的共模中。
任何人都可以用人类语言解释这两个吗?
答案 0 :(得分:182)
运行循环是一种允许系统唤醒休眠线程以便它们可以管理异步事件的机制。通常,当您运行一个线程(主线程除外)时,有一个选项可以在运行循环中启动线程。如果线程运行某种排序或长时间运行的操作而不与外部事件交互且没有定时器,则不需要运行循环,但如果您的线程需要响应传入事件,则应将其附加到运行循环以便新事件到来时唤醒线程。这是NSURLConnection
生成的线程的情况,因为它们仅在传入事件(来自网络)时唤醒。
每个线程可以与多个运行循环相关联,或者可以与可以设置为在不同模式下工作的特定运行循环相关联。 “运行循环模式”是操作系统用来建立某些规则,用于何时传递某些事件或收集它们以便稍后交付。
通常所有运行循环都设置为“默认模式”,它建立了管理输入事件的默认方式。例如:只要鼠标拖动(Mac OS)或触摸(在iOS上)事件发生,则此运行循环的模式将设置为事件跟踪;这意味着线程不会在新的网络事件中被唤醒,但是这些事件将在用户输入事件终止并且运行循环再次设置为默认模式时传递;显然,这是OS架构师为了优先考虑用户事件而不是后台事件而做出的选择。
如果您决定使用NSURLConnection
更改scheduleInRunLoop:forModes:
线程的运行循环模式,则可以将线程分配给特殊的运行循环模式,而不是比特定的默认运行循环。许多输入源(包括事件跟踪)使用称为NSRunLoopCommonModes
的特殊伪模式。例如,将NSURLConnection
的实例分配给共同模式意味着除了“默认模式”之外还将其事件与“跟踪模式”相关联。将线程与NSRunLoopCommonModes
相关联的一个优点/缺点是线程不会被触摸事件阻止。
新模式可以添加到常用模式,但这是一个非常低级别的操作。
我想在最后添加一些注释:
通常我们需要使用一组图像或
使用表格视图从网络下载的缩略图。我们可能会这么认为
在表格视图中从网络下载这些图像
滚动可以改善用户体验(因为我们可以看到图像
滚动),但这是不利的,因为流动性
滚动会受到很大影响。在这个带有NSURLConnection
的示例中,不应使用运行循环;最好使用UIScrollView
委托方法来检测滚动何时终止,然后更新表并下载新项
来自网络;
您可以考虑使用GCD来帮助您“屏蔽”您的代码 来自运行循环管理问题。在上面的例子中,你可以 考虑将您的网络请求添加到自定义串行队列。