RunLoop相关

概念

RunLoop是通过内部维护的事件循环来对事件/消息进行管理的一个对象

  • 事件循环:CPU-内核态和用户态
    ① 没有消息需要处理的时候会休眠以减少资源占用(由用户态转向内核态);
    ② 有消息需要处理的时候会被立刻唤醒(有内核态转向用户态)。
  • main函数为什么可以一直运行而不退出
    UIApplicationMain方法在内部维护了一个主线程RunLoop,RunLoop又是一种对事件的维护机制,可以做到有事做就唤醒做事,没事做就休眠等待,也就是用户态到内核态来回的转换。

数据结构

NSRunLoop(Foundation)是CFRunLoop(CoreFoundation)的封装,提供了面向对象的API
CFRunLoop:RunLoop对象
CFRunLoopMode:运行模式
CFRunLoopSource:输入源/事件源
CFRunLoopTimer:定时源
CFRunLoopObserver:观察者

  • CFRunLoopTimer
    基于时间的触发器,基本上说的就是NSTimer。在预设的时间点唤醒RunLoop执行回调。因为它是基于RunLoop的,因此它不是实时的(就是NSTimer 是不准确的。 因为RunLoop只负责分发源的消息。如果线程当前正在处理繁重的任务,就有可能导致Timer本次延时,或者少执行一次)。
  • 各数据结构之间的联系
    线程和RunLoop一一对应, RunLoop和Mode是一对多的,Mode和source、timer、observer也是一对多的
    各数据结构之间的联系
  • RunLoop的Mode
    关于Mode首先要知道一个RunLoop 对象中可能包含多个Mode,且每次调用 RunLoop 的主函数时,只能指定其中一个 Mode(CurrentMode)。切换 Mode,需要重新指定一个 Mode 。主要是为了分隔开不同的 Source、Timer、Observer,让它们之间互不影响。
    当RunLoop运行在Mode1上时,是无法接受处理Mode2或Mode3上的Source、Timer、Observer事件的
    RunLoop的Mode

    总共是有五种CFRunLoopMode:
    kCFRunLoopDefaultMode:默认模式,主线程是在这个运行模式下运行
    UITrackingRunLoopMode:跟踪用户交互事件(用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他Mode影响)
    UIInitializationRunLoopMode:在刚启动App时第进入的第一个 Mode,启动完成后就不再使用
    GSEventReceiveRunLoopMode:接受系统内部事件,通常用不到
    kCFRunLoopCommonModes:伪模式,不是一种真正的运行模式,是同步Source/Timer/Observer到多个Mode中的一种解决方案

事件循环机制

这张图在网上流传比较广

对于RunLoop而言最核心的事情就是保证线程在没有消息的时候休眠,在有消息时唤醒,以提高程序性能。RunLoop这个机制是依靠系统内核来完成的(苹果操作系统核心组件Darwin中的Mach)。

RunLoop通过mach_msg()函数接收、发送消息。它的本质是调用函数mach_msg_trap(),相当于是一个系统调用,会触发内核状态切换。在用户态调用 mach_msg_trap()时会切换到内核态;内核态中内核实现的mach_msg()函数会完成实际的工作。
即基于port的source1,监听端口,端口有消息就会触发回调;而source0,要手动标记为待处理和手动唤醒RunLoop
Mach消息发送机制
大致逻辑为:
1、通知观察者 RunLoop 即将启动。
2、通知观察者即将要处理Timer事件。
3、通知观察者即将要处理source0事件。
4、处理source0事件。
5、如果基于端口的源(Source1)准备好并处于等待状态,进入步骤9。
6、通知观察者线程即将进入休眠状态。
7、将线程置于休眠状态,由用户态切换到内核态,直到下面的任一事件发生才唤醒线程。

  • 一个基于 port 的Source1 的事件(图里应该是source0)。
  • 一个 Timer 到时间了。
  • RunLoop 自身的超时时间到了。
  • 被其他调用者手动唤醒。

8、通知观察者线程将被唤醒。
9、处理唤醒时收到的事件。

  • 如果用户定义的定时器启动,处理定时器事件并重启RunLoop。进入步骤2。
  • 如果输入源启动,传递相应的消息。
  • 如果RunLoop被显示唤醒而且时间还没超时,重启RunLoop。进入步骤2
    10、通知观察者RunLoop结束。

RunLoop与NSTimer

  • RunLoop与NSTimer的关系
    NSTimer在预设的时间点唤醒RunLoop执行回调。因为它是基于RunLoop的,因此它不是实时的(就是NSTimer 是不准确的。 因为RunLoop只负责分发源的消息。如果线程当前正在处理繁重的任务,就有可能导致Timer本次延时,或者少执行一次)。
  • 一个比较常见的问题:滑动tableView时,定时器还会生效吗?
    默认情况下RunLoop运行在kCFRunLoopDefaultMode下,而当滑动tableView时,RunLoop切换到UITrackingRunLoopMode(为了跟踪用户交互事件),而Timer是在kCFRunLoopDefaultMode下的,就无法接受处理Timer的事件。
    怎么去解决这个问题呢?把Timer添加到UITrackingRunLoopMode上并不能解决问题,因为这样在默认情况下就无法接受定时器事件了。
    所以我们需要把Timer同时添加到UITrackingRunLoopModekCFRunLoopDefaultMode上。
    那么如何把timer同时添加到多个mode上呢?就要用到NSRunLoopCommonModes了
[[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];

这样Timer就被添加到多个mode上,这样即使RunLoop由kCFRunLoopDefaultMode切换到UITrackingRunLoopMode下,也不会影响接收Timer事件。

RunLoop与多线程

线程是和RunLoop一一对应的
自己创建的线程默认是没有RunLoop的。

  • 怎样实现一个常驻线程
    ① 为当前线程开启一个RunLoop
    ② 向该RunLoop中添加一个Port/Source等维持RunLoop的事件循环
    ③ 启动该RunLoop

  • 怎样实现子线程数据回来更新UI的时候不打断用户的滑动操作
    用户滑动操作时,当前RunLoop时处在UITrackingRunLoopMode模式下的,将子线程数据刷新UI的相关部分可以分配到RunLoop的kCFRunLoopDefaultMode模式下,这样用户在滑动操作时,是不会处理kCFRunLoopDefaultMode模式下的任务的。

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

推荐阅读更多精彩内容

  • 一.Runloop是什么 通俗点来说,我们有一个线程,当我们需要它处理事件时,它要随时启动,我们不需要它时,它要随...
    MichealXXX阅读 155评论 0 0
  • 一、谈谈对RunLoop的使用理解 保持程序持续运行,程序一启动就会开一个主线程,主线程一开起来就会跑一个主线程对...
    Evans_Xiao阅读 63评论 0 0
  • 转自bireme,原地址:https://blog.ibireme.com/2015/05/18/runloop/...
    乜_啊_阅读 1,385评论 0 5
  • 转自http://blog.ibireme.com/2015/05/18/runloop 深入理解RunLoop ...
    飘金阅读 990评论 0 4
  • 原文地址:http://blog.ibireme.com/2015/05/18/runloop/ RunLoop ...
    大饼炒鸡蛋阅读 1,160评论 0 6