RunLoop

在我们平时的开发过程中会涉及到RunLoop的开发其实是非常少的,但是RunLoop其实是保证App能够正常运行的一个非常关键的东西。

什么是RunLoop?
我们现在的手机系统都是一个事件驱动模式的系统,当用户触发了某个事件,系统会快速的进行响应处理。一般的线程都是从开始直接走到结束的一个直线型的过程,结束后线程就被释放了。而RunLoop的存在就是为了能保持线程的持续存在,当有需要的时候进行激活处理事件,不需要的时候进行挂起休眠等待下一次的事件激活。

普通的线程
添加RunLoop的线程

RunLoop的作用
1、使程序一直保持运行并能在用户有输入操作的时候进行处理
2、决定程序在任何应该处理哪些事情
3、调用解耦,消息队列
4、节省CPU时间(在没有需要处理的消息的时候进行挂起休眠)

这里对2、3进行解释一下,当用户进行操作APP的时候肯定不是仅仅触发某一个事件的,必定是会触发一系列的事件。这时候RunLoop会有个管理的消息队列来做管理,先处理哪个再处理哪个。这时候用户的消息触发与程序的处理其实就解耦分开了,用户只需要做自己的操作,剩下的都交给程序自己去做管理处理。

RunLoop的机制
在我们运行的APP中打上断点并进行触发,看看调用栈

调用堆栈

我现在是断在了一个button的点击触发事件那里。我们看看调用堆栈里面的调用顺序。
最下面的start,main是整个程序的起调,然后到了UIKit里面的Main函数,GSEventRunModel这个是物理内核对用户的点击各种触发事件的处理,然后就调到了RunLoop这里,获取了点击事件然后进行事件消息处理分发,到最上的就是我们熟悉的各种层层函数的调用。

我们这边看到箭头指的这个一长串东西,其实是RunLoop的六种起调状态,我们的绝大部分都是从这六种状态进行调起的,但也并不是绝对,如果自己创建一个线程去调用方法,是有可能不从这六个状态进行调起方法的

image.png

这里面的CAllING_OUT其实就可以看出来作用是进行调出的,主要看的是标红的地方
这边解释一下最下面两个Source0和Source1
Source0:处理APP内部事件,APP自己负责管理(触发)例如UIEvent
Source1:由RunLoop和内核管理,Mach port驱动

Mach port
轻量级的进程通讯,有点类似于网络通讯端口,比方说手机的定位、网络数据下载,都是手机通过调接口传入到APP内再调到相应的函数

当Xcode点击暂停按钮,APP就会处于一个挂起的trap状态
当另一个线程(或者另一个进程中的某个线程)向内核发消息,trap状态就会被唤醒,进行事件处理

RunLoop的结构

结构

这张是从其他地方扒过来的图

RunLoop与线程的关系
在我的理解中,RunLoop是依托于线程的,但是并不是所有线程都会有RunLoop的。线程刚创建时并没有 RunLoop,如果你不主动获取,那它一直都不会有。RunLoop 的创建是发生在第一次获取时,RunLoop 的销毁是发生在线程结束时。你只能在一个线程的内部获取其 RunLoop(主线程除外)。

CFRunLoopTimer
NSTimer是对这个的一个上层封装
除了GCD的timer其他的timer都是基于RunLoop来实现的

CFRunLoopSource
类似于一个协议Protocol,当符合条件则触发
在RunLoop里面自己定义了两个,一个是Source0一个是Source1
听说还可以自己定义,这里没有仔细研究

CFRunLoopObserver

枚举

向外部报告现在的状态

这个与Autorelease Pool的关系
Autorelease Pool
在App启动后, 系统会在主线程里先注册两个Observer, 回调都是_wrapRunLoopWithAutoreleasePoolHandler()
Observer1: 监视即将进入RunLoop, 在这个回调内会去调用_objc_autoreleasePoolPush()来创建一个自动释放池, 它的order是-2147483647, 最高优先级, 酱紫就可以保证创建自动释放池是在其他回调之前
Observer2: 监听了两件事
第一: 在即将进入休眠(BeforeWaiting)的时候调用_objc_autoreleasePoolPop()和_objc_autoreleasePoolPush()
第二: 在即将退出RunLoop(Exit)的时候调用_objc_autoreleasePoolPop()来释放自动释放池
注意: 这个Observer2的order是2147483647, 优先级最低, 酱紫就可以保证在处理完所有事情之后再去释放这个自动释放池
我们在主线程中执行的代码, 一般都是写在事件回调, Timer回调内, 酱紫回调就会被RunLoop所创建的自动释放池(Autorelease Pool)里循环着, 我们不用去担心内存泄漏什么之类的, 也不需要去显示的去创建Pool

Mode
一个 RunLoop 包含若干个 Mode,每个 Mode 又包含若干个 Source/Timer/Observer。每次调用 RunLoop 的主函数时,只能指定其中一个 Mode,这个Mode被称作 CurrentMode。如果需要切换 Mode,只能退出 Loop,再重新指定一个 Mode 进入。这样做主要是为了分隔开不同组的 Source/Timer/Observer,让其互不影响。

RunLoop与GCD
RunLoop和GCD其实是协调的关系,当GCD触发在主线程dispatch_get_main_queue()做事情的时候,RunLoop做的是帮GCD进行调起

实践
1、保持线程的长久存活
2、通过切换mode来进行不同事件的调用时机控制

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

推荐阅读更多精彩内容