深入理解runloop

线程中的runloop

在开发中,我们会经常接触到线程,比如在主线程中更新UI,在子线程中异步请求等,而线程中最重要的一个组成部分便是runloop,其是用来管理线程的。runloop在线程中有以下两个作用:

  1. 保证线程不退出
  2. 监听并处理事件,使得线程有事件时工作,无事件时睡眠

每个线程中都有一个runloop,主线程中的runloop是在应用程序启动时创建的,默认是开启的,子线程中的runloop采用的是延迟加载的方式,如果我们不主动获取,子线程的runloop是不会创建的。

解析runloop

runloop三要素: Modes(模式)、sources(源)、Observers(观察者)。当有事件源触发时,runloop会被唤醒并处理事件源的方法,并通知该runloop运行模式下的所有观察者。

Run Loop Modes(运行循环模式)

运行循环在工作时,会有多种运行模式。我们常用到的模式有:NSDefaultRunLoopMode和NSRunLoopCommonModes 。每个RunLoop Mode都可以看作是一个集合,其中包含了其监听的事件源以及在事件发生时需要通知的RunLoop Observers。在相应的模式下,只有对应于该模式的source会被处理,同样也只有对应于该模式的observer会被通知。其实运行循环模式起到一个过滤作用,可以过滤到我们不关心的其他的source事件。

Cocoa 和 Core Foundation框架定义了一个默认的和一些常用的运行循环模式,如下表:

Mode Name Description
Default NSDefaultRunLoopMode (Cocoa) kCFRunLoopDefaultMode (Core Foundation) 默认模式,一般设置为此模式.
Connection NSConnectionReplyMode (Cocoa) Cocoa用该模式来监听NSConnection请求的回复,该模式为系统使用,我们一般不会用到
Modal NSModalPanelRunLoopMode (Cocoa) Cocoa 用此模式来区分 modal panels事件.
Event tracking NSEventTrackingRunLoopMode (Cocoa) Cocoa 在该模式下,限制其他source的事件
Common modes NSRunLoopCommonModes (Cocoa)kCFRunLoopCommonModes (Core Foundation) 这是一个可配置的模式组,在该模式下的source 事件,和模式组里的其他模式都会产生联系。在Cocoa框架中,该模式默认包含Default、Modal和 Event tracking 三种模式,在Core Foundation中默认只包含Default模式,我们可以用CFRunLoopAddCommonMode 函数来添加自定义的模式。
Run Loop Sources

先来看runloop和sources的结构图

runloop.png

runloop可以监听并处理事件,其监听的事件源有两种类型:Input sources(输入源) 和** Timer sources(定时器源)**。输入源异步传递事件到线程中,通常消息来自其它线程或不同的应用,定时器源同步传递事件。

  • Input sources
    输入源异步发送事件到线程中,输入源共有两种类型:一种是基于端口的输入源(Port-based input sources),一种是自定义输入源(Custom input sources)。基于端口的数据源监听应用的Mach端口,自定义输入源监听自定义的事件源,二者的唯一区别是:基于端口的输入源的信号是由内核自动触发的,自定义输入源的信号是由其它线程手动触发的。
  • Port-Based Sources
    Cocoa 和 Core Foundation框架给我们提供了一些创建基于端口的源的对象和函数。
    在 Cocoa中,我们只需要创建一个 NSPort对象,并将其添加到运行循环中就可以了,NSPort对象会自己创建输入源。

     NSPort *port = [NSPort port];
     [port scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    

    但是在Core Foundation中,我们就需要手动创建端口和输入源,我们可以用CFMachPortRef, CFMessagePortRef, or CFSocketRef来创建相应的对象

  • Custom input sources
    我们也可以自定义输入源,自定义输入源时,我们需要配置定义输入源的行为,运行循环模式,输入源事件的传递机制,以及销毁输入源等。

  • Cocoa Perform Selector Sources
    除了基于端口的源,Cocoa也定义了自定义输入源--Perform Selector Sources,这使得我们可以在任意线程中执行我们的方法,Perform Selector 的方法在目标线程中是串行执行的,这样就解决了多个方法在一个线程中执行的同步问题,和基于端口的源不同,Perform Selector 在方法执行完成之后,会将自己从runloop中移除。

Note: 当我们在目标线程上执行我们的方法时,目标线程的运行循环必须开启,否则方法不会执行。主线程的运行循环默认开启,子线程的运行循环默认不开启,因此我们想要在子线程上运行我们的程序,需要手动开启子线程的运行循环。

  • Timer Sources(定时器源)
    定时器源发送同步事件到我们的线程中,对于线程来说,定时器是一种通知自己做一些事情的方式。虽然,定时器源会发出基于时间的通知,但是定时器并不是实时机制,跟输入源一样,定时器源也跟runloop的运行模式相关,如果定时器的模式,不在运行循环当前监控的模式中,定时器方法是不会执行的。另外如果定时器触发时,运行循环正在执行操作,定时器将会在下次运行循环调用时触发。
Run Loop Observers

运行循环在运行时,会发出一些通知,我们可以通过注册Observers来监听运行循环当前所处的状态,运行循环状态有以下几种:

  • 即将进入运行循环
  • 运行循环将要处理定时器
  • 运行循环将要处理输入源
  • 运行循环将要进入睡眠
  • 运行循环被唤醒,但是还未处理事件
  • 运行循环退出
The Run Loop Sequence of Events(运行循环执行事件的顺序)
  1. 通知观察者即将进入运行循环
  2. 通知观察者将要处理定时器事件
  3. 通知观察者将要处理输入源(基于端口的源除外)事件
  4. 处理输入源(基于端口的源除外)事件
  5. 如果有基于端口的输入源事件,则立即处理。然后跳到第9步。
  6. 通知观察者线程将要进入休眠
  7. 线程进入休眠,等待被唤醒,下列事件可以唤醒线程
  • 基于端口的源的事件
  • 定时器事件
  • 设置的runloop超时时间到期
  • runloop主动被唤醒
  1. 通知观察者线程刚被唤醒
  2. 处理挂起的事件
  • 如果有用户定义的定时器事件触发,处理定时器事件,并且重启运行循环,进入第2步
  • 如果触发的是输入源事件,传送事件
  • 如果runloop被主动唤醒,并且没有超时,重启runloop,进入第2步.
  1. 通知观察者运行循环将要退出

代码示例后续会整理分享

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

推荐阅读更多精彩内容