NSRunloop简单细说(六)—— 几种循环模式详细解析

版本记录

版本号 时间
V1.0 2017.08.23

前言

NSRunloopOC Foundation框架中非常重要的一个类,很多时候我们会使用它,但是未必对其有深入的了解,接下来几篇我就会带着大家重新学习一下NSRunloop这个类,从简单到复杂,从基本到深化,我会一步步的走完。希望对大家有所帮助。感兴趣的可以看我上一篇。
1. NSRunloop简单细说(一)—— 整体了解
2. NSRunloop简单细说(二)—— 获取运行循环及其模式
3. NSRunloop简单细说(三)—— 定时器和端口
4. NSRunloop简单细说(四)—— 开启Runloop
5. NSRunloop简单细说(五)—— 调度和取消消息

几种循环模式简介

关于循环模式可以参考文档

运行循环模式是要监视的输入源和定时源的集合,以及要通知的运行循环观察器的集合。 每次运行运行循环时,都可以指定(显式地或隐式地)运行一个特定的“模式”。 在运行循环的通过期间,仅监视与该模式相关联的源,并允许其传递其事件。 (同样,只有与该模式关联的观察者才会被通知运行循环的进度。 与其他模式相关联的源将持续到任何新事件,直到以适当模式通过循环。

在您的代码中,您可以按名称识别模式。CocoaCore Foundation都定义了默认模式和几种常用模式,以及用于在代码中指定这些模式的字符串。 您可以通过简单地为模式名称指定自定义字符串来定义自定义模式。 虽然您分配给自定义模式的名称是任意的,但这些模式的内容不是。 您必须确保将一个或多个输入源,计时器或运行循环观察器添加到您创建的任何模式,使其有用。

您可以使用模式在特定通过运行循环的过程中过滤来自不需要的源的事件。 大多数情况下,您将要在系统定义的“默认”模式下运行运行循环。 但是,模态面板可能会以“模态”模式运行。 在此模式下,只有与模式面板相关的来源才会将事件传递给线程。 对于辅助线程,可以使用自定义模式来防止低优先级源在时间紧迫的操作期间传递事件。

这里还要注意:模式根据事件的来源进行区分,而不是事件的类型。 例如,您不会使用模式仅匹配鼠标向下事件或仅匹配键盘事件。 您可以使用模式来监听不同的端口集,临时暂停定时器,或以其他方式更改源和运行当前正在监视的循环观察器。

其实前面我们都已经简要的说了一下NSRunloop的几种循环模式了,这一篇主要就是扩展,详细的说一下这几种循环模式。

FOUNDATION_EXPORT NSRunLoopMode const NSDefaultRunLoopMode;
FOUNDATION_EXPORT NSRunLoopMode const NSRunLoopCommonModes NS_AVAILABLE(10_5, 2_0);
typedef NSString * NSRunLoopMode NS_EXTENSIBLE_STRING_ENUM;

系统为我们提供了多种模式,如下所示:

  • Default模式

  • Connection模式

    • 定义:NSConnectionReplyMode(Cocoa)描述:处理NSConnection对象相关事件,系统内部使用,用户基本不会使用。
  • Modal模式

    • 定义:NSModalPanelRunLoopMode(Cocoa)描述:处理modal panels事件。
  • Event tracking模式

    • 定义:UITrackingRunLoopMode(iOS) NSEventTrackingRunLoopMode(cocoa)描述:在拖动loop或其他user interface tracking loops时处于此种模式下,在此模式下会限制输入事件的处理。例如,当手指按住UITableView拖动时就会处于此模式。
  • Common模式

    • 定义:NSRunLoopCommonModes (Cocoa) kCFRunLoopCommonModes (Core Foundation)描述:这是一个伪模式,其为一组run loop mode的集合,将输入源加入此模式意味着在Common Modes中包含的所有模式下都可以处理。在Cocoa应用程序中,默认情况下Common Modes包含default modes , modal modes ,event Tracking modes。可使用CFRunLoopAddCommonMode方法想Common Modes中添加自定义modes。
几种运行模式

下面我们就详细的研究一下这几个运行模式。


一、NSDefaultRunLoopMode

这个是默认的运行模式,也是最常用的运行模式,NSTimerNSURLConnection默认运行该模式下,所以如果我们不改变定时器的运行模式,让他在这个模式下运行,那么当我们拖动控件的时候,变为UITrackingRunLoopMode模式时,NSTimer就不能响应了,解决方法就是将定时器加入到UITrackingRunLoopModeNSRunLoopCommonModes。另外,还有一种方法就是:将 Timer 加入到顶层的 RunLoopcommonModeItems 中。commonModeItems被 RunLoop 自动更新到所有具有Common属性的 Mode 里去。

默认模式是用于大多数操作的模式。 大多数情况下,您应该使用此模式启动运行循环并配置输入源。一般用于处理NSConnection对象以外的输入源的模式


二、NSConnectionReplyMode

Cocoa将此模式与NSConnection对象结合使用来监视回复。 你很少需要自己使用这种模式。


三、NSModalPanelRunLoopMode

Cocoa使用此模式来识别用于模式面板的事件。


四、UITrackingRunLoopMode

Cocoa使用此模式在鼠标拖动循环和其他类型的用户界面跟踪循环期间限制传入事件。


五、NSRunLoopCommonModes

这是一组可配置的常用模式。 将输入源与此模式相关联还将其与组中的每种模式相关联。 对于Cocoa应用程序,默认情况下,此设置包括default, modal, 和event trackingCore Foundation最初只包含默认模式。 您可以使用CFRunLoopAddCommonMode函数向该集合添加自定义模式。

主线程的 RunLoop 里有两个预置的 Mode:kCFRunLoopDefaultModeUITrackingRunLoopMode。这两个 Mode 都已经被标记为”Common”属性。

这里还要说一下底层的东西,CFRunLoopMode,这个是NSRunLoopMode在C语言的底层,是一个结构体,如下所示。

struct __CFRunLoopMode {
    CFStringRef _name;            // Mode Name, 例如 @"kCFRunLoopDefaultMode"
    CFMutableSetRef _sources0;    // Set
    CFMutableSetRef _sources1;    // Set
    CFMutableArrayRef _observers; // Array
    CFMutableArrayRef _timers;    // Array
    ...
};

下面也顺便看一下NSRunLoop的C语言底层。

struct __CFRunLoop {
    CFMutableSetRef _commonModes;     // Set
    CFMutableSetRef _commonModeItems; // Set<Source/Observer/Timer>
    CFRunLoopModeRef _currentMode;    // Current Runloop Mode
    CFMutableSetRef _modes;           // Set
    ...
};

这里有个概念叫 CommonModes:一个 Mode 可以将自己标记为Common属性(通过将其 ModeName 添加到 RunLoop 的 “commonModes” 中)。每当 RunLoop 的内容发生变化时,RunLoop 都会自动将 _commonModeItems 里的 Source/Observer/Timer 同步到具有 “Common” 标记的所有Mode里。

CFRunLoop对外暴露的管理 Mode 接口只有下面2个:

CFRunLoopAddCommonMode(CFRunLoopRef runloop, CFStringRef modeName);
CFRunLoopRunInMode(CFStringRef modeName, ...);

Mode 暴露的管理 mode item 的接口有下面几个:

CFRunLoopAddSource(CFRunLoopRef rl, CFRunLoopSourceRef source, CFStringRef modeName);
CFRunLoopAddObserver(CFRunLoopRef rl, CFRunLoopObserverRef observer, CFStringRef modeName);
CFRunLoopAddTimer(CFRunLoopRef rl, CFRunLoopTimerRef timer, CFStringRef mode);
CFRunLoopRemoveSource(CFRunLoopRef rl, CFRunLoopSourceRef source, CFStringRef modeName);
CFRunLoopRemoveObserver(CFRunLoopRef rl, CFRunLoopObserverRef observer, CFStringRef modeName);
CFRunLoopRemoveTimer(CFRunLoopRef rl, CFRunLoopTimerRef timer, CFStringRef mode);

你只能通过 modeName 来操作内部的 mode,当你传入一个新的modeName 但 RunLoop 内部没有对应 mode 时,RunLoop会自动帮你创建对应的 CFRunLoopModeRef。对于一个 RunLoop 来说,其内部的 mode 只能增加不能删除。

参考文章

1. iOS中NSRunLoop的模式
2. 深入理解RunLoop

后记

未完,待续~~~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,026评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,655评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,726评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,204评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,558评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,731评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,944评论 2 314
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,698评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,438评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,633评论 2 247
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,125评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,444评论 3 255
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,137评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,103评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,888评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,772评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,669评论 2 271

推荐阅读更多精彩内容