RunLoop(基础部分)

在很多地方,都能看到这个概念,却不知道到底是个什么玩意,网上写的也很抽象,理解起来很吃力,官方文档官方文档也只是泛泛而谈。


那么,什么是RunLoop?

苹果在取名方面我觉得非常不错,runloop就像字面上的意思一样运行循环,俗称“兜圈圈”。也就是死循环,在这个循环中,会去处理一系列的事件。假如说这个循环停止了,那么程序就已经停止了。

死循环

在创建一个工程,都会有个main函数,在这个函数里就是去运行程序的时候创建了个主线程的RunLoop,也是保持程序持续运行的关键。

如果改成return 0;那么程序将不会持续运行,刚运行就停止了。也不会去处理app的各种事件,这也是为什么要去使用RunLoop了,同样,在其他操作系统上也有这个概念。

请问这个打印会正常打印出来么?可以先思考下为什么。

答案是不会打印的,因为在上一句,就成死循环,也就是弄了个runloop,一直卡在上一句代码,也就是保持了程序的持续运行,如果说能打印,那么return也能返回值,那么程序就没法持续保持运行,一旦返回值那么意味着结束。


RunLoop有什么用呢?

1.保持程序的持续运行

2.处理App的各种事件(比如触摸事件、定时器事件、Selector事件)

3.节省CPU资源,提高程序性能。(该做事的时候做事,该休息的时候休息)


RunLoop对象

在iOS中有2套API去访问和使用RunLoop

Foundation框架

NSRunLoop

Core Foundation框架

CFRunLoopRef

NSRunLoop和CFRunLoopRef都代表RunLoop对象,NSRunLoop是基于CFRunLoopRef的一层OC封装,为此要理解RunLoop内部结构,要多研究CFRunLoopRef

NSRrunLoop缺点:效率低(因为是上层封装),封装的不算好,可提供的方法很少。

CFRunLoopRef是开源的,开源地址CFRunLoopRef开源地址


RunLoop和线程

1.每条线程都有唯一的一个与之对应的RunLoop对象

2.主线程的RunLoop已经自动创建好了,子线程的RunLoop需要主动创建(默认关闭的)

3.RunLoop在第一次获取时创建,在线程结束时销毁。


如何获取RunLoop对象

Foundation框架

[NSRunLoop currentRunLoop];//获取当前线程的RunLoop对象

[NSRunLoop mainRunLoop];//获取主线程的RunLoop对象

Core Foundation

CFRunLoopGetCurrent();//获取当前线程的RunLoop对象

CFRunLoopGetMain();//获得主线程的RunLoop对象


RunLoop相关类

类层次结构图

Core Foundation中关于RunLoop有5个类

CFRunLoopRef

CFRunLoopModeRef

CFRunLoopSourceRef

CFRunLoopTimerRef  

CFRunLoopObserverRef

RunLoop中有多个Mode,可以在多个Mode中来回切换,Mode是RunLoop重要的组成部分,没有Mode,RunLoop就跑不起来.

在一个Mode里,不是必须Source,Timer,Observer三个必须有值,有一个有值,RunLoop也是可以跑起来的。


CFRunLoopModeRef

1.CFRunLoopModeRef代表RunLoop的运行模式

2.一个RunLoop包含若干个Mode,每个Mode又包含若干个Source/Timer/Observer

3.每次RunLoop启动时,只能指定其中一个Mode,这个Mode又叫做CurrentMode

4.如果需要切换Mode,只能退出Loop,再重新指定一个Mode进入Loop。这样做主要是为了分隔不同组的Source/Timer/Observer,让其互不影响。

系统默认注册了5个Mode:

kCFRunLoopDefaultMode:app默认Mode,通常主线程是在这个Mode下运行

UITrackingRunLoopMode:界面跟踪Mode,用于Scrollview追踪触摸滑动,保证界面滑动不受其他Mode影响

UIInitializationRunLoopMode:在刚启动App时进入的第一个Mode,启动完成后就不再使用

GSEventReceiveRunLoopMode:接受系统时间的内部Mode,通常用不到

kCFRunLoopCommonModes:这是一个占位用的Mode,不是一种真正的Mode,即可能kCFRunLoopDefaultMode,也可能是UITrackingRunLoopMode

例子:

当不去滑动TextView时,当前RunLoopMode是NSDefaultMode,所以定时器会正常运作;当去滑动TextView时,当前RunLoopMode切换到UITrackingRunLoopMode,定时器又要在NSDefaultMode模式下才能运行,所以定时器失效;当不再滑动,又切换到NSDefaultMode,定时器又可以正常运作。

我们知道了是因为RunLoop模式导致了,所以,将定时器在的模式更改就行了。

[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];


CFRunLoopSourceRef

Mode的一个组成部分,CFRunLoopSourceRef被称为事件源(输入源)。RunLoopSource包括2种source:分别为Source0Source1

Source0:非基于port的

只包含了一个回调(函数指针),它并不能主动触发事件。使用时,你需要先调用。(通俗点说:1.自定义的事件,自己写的事件;2.PerformSelecter事件)

Source1:基于port的

包含了一个 mach_port 和一个回调(函数指针),被用于通过内核和其他线程相互发送消息。这种 Source 能主动唤醒 RunLoop 的线程(简单地说:系统做的事件)

(补充:port就是端口内核的意思,也可以理解为cpu)

上图是我在storyboard拖的button事件方法,通过设置断点,可以看到线程栈的情况,很清楚的看到Source0,也可以说明,事件源是由自定义写的。


CFRunLoopTimerRef

基于时间的触发器(说白了,基本就是NSTimer)


CFRunLoopObserverRef

CFRunLoopObserverRef是观察者,能够监听RunLoop的状态改变

可以监听的时间点有下面几个

/*Run Loop Observer Activities*/

typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity){

       kCFRunLoopEntry = (1UL << 0),        //即将进入RunLoop

       kCFRunLoopBeforeTimers = (1UL << 1),  //即将处理Timer

       kCFRunLoopBeforeSources = (1UL << 2), //即将处理Source

       kCFRunLoopBeforeWaiting = (1UL << 5), //即将进入休眠

       kCFRunLoopAfterWaiting = (1UL << 8),  //刚从休眠中唤醒

       kCFRunLoopExit = (1UL << 7),         //即将退出RunLoop

       kCFRunLoopAllActivities = 0x0FFFFFFFU   //监听RunLoop所有情况

}

如何去创建一个ObserverRef

列1:我们来看看应用从启动到界面显示,runloop状态是如何变化的。

可以看到,从最开始的1(即将进入RunLoop)到最后的32(即将进入休眠)一个过程。

列1:我们来监听下一个按钮点击后,RunLoop状态的变化

可以看到,从最开始的64(刚从休眠唤醒)到最后的32(即将进入休眠)。

为此,我们可以利用runloop的状态改变来处理一些不好处理的事件,具体需要具体情况而定,这样runloop就可以很好的结合起来使用了。


知道了RunLoop逻辑处理和RunLoop结构后,我们来看看官方提供的RunLoop处理逻辑图就很好理解了。

左图的就是RunLoop,Runloop是跟线程一一绑定的,所以是个Thread。然后Runloop一直跑圈,在跑圈的过程中,右图会有Sources传入进行事件操作,如Timer,基于Port事件,自定义事件,performSelector事件。

RunLoop处理逻辑过程


总结:

    1.主线程的RunLoop默认开启

    2.子线程的RunLoop默认关闭,需要手动开启

    3.RunLoop开启的时候要包含Mode,必须要某个确定的模式下运行,同时在一个模式下运行

    4.observer可以监听RunLoop所有状态事件,可以做到一些别人做不到的事。


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

推荐阅读更多精彩内容