关于Runloop的理解

一、Runloop简介

概念:

从字面上来看,RunLoop是运行循环的意思,实质上,RunLoop是一种寄生于线程的消息循环机制,让线程能随时处理事件但不退出,保证线程的存活,而不是线程执行完任务后就消亡。

RunLoop实际上是一个对象,这个对象管理了其需要处理的事件和消息,并提供了一个入口函数来执行Event Loop的逻辑。线程执行了这个函数后,就会一直处于这个函数内部接受消息→等待→处理的循环中,直到达到循环结束条件退出(比如传入 quit 的消息),函数返回。让线程在没有消息处理时休眠以避免资源占用、在有消息到来时立刻被唤醒。

特性:

  1. 每一个线程都有一个对应的RunLoop对象,主线程默认开启RunLoop,这能保证应用程序的执行运行,接收并处理各种事件;子线程默认不开启。

  2. RunLoop有三种启动方式:runrunUntilDate:runMode:beforeDate:
    第一种无条件永远运行RunLoop并且无法停止,线程永远存在。第二种会在时间到后退出RunLoop,同样无法主动停止RunLoop。前两种都是在NSDefaultRunLoopMode模式下运行。第三种可以选定运行模式,并且在时间到后或者触发了非Timer的事件后退出。

  3. RunLoop能正常运行的条件:运行在添加了至少一个事件源(Timer/Source/Observer)mode下,否则会自动退出。经过NSRunLoop封装之后,只可以往mode中添加两类事件:NSPortNSTimer

五个类:

  • CFRunLoopRef:RunLoop对象
  • CFRunLoopModeRef:RunLoop的运行模式
  • CFRunLoopSourceRef:事件产生的地方
  • CFRunLoopTimerRef:定时器(NSTimer)
  • CFRunLoopObserverRef:观察者,回调Runloop状态

iOS 中的RunLoop:

在iOS系统中,提供了两种RunLoop对象:NSRunLoopCFRunLoopRef

  • CFRunLoopRef是在CoreFoundation框架内,它提供了面向过程的纯C函数API

  • NSRunLoop是基于CFRunLoopRef的封装,提供了面向对象的API

两者最主要的区别在于:NSRunLoop是非线程安全的,意味着只能在当前线程中获取线程对应的RunLoop(主线程RunLoop除外),而CFRunLoopRef是线程安全的。

我们不能够手动创建RunLoop,系统为我们提供了获取的方法

[NSRunLoop currentRunLoop]; //获取当前线程的RunLoop
[NSRunLoop mainRunLoop]; //获取主线程的RunLoop
CFRunLoopGetMain(); //获取当前线程的RunLoop
CFRunLoopGetCurrent(); //获取主线程的RunLoop

作用:

  1. 让主线程一直处于收发消息的状态,不会自动结束,保证了程序的运行
  2. 处理App中的各种事件(比如触摸事件、定时器事件等)
  3. 节省CPU资源,提高程序性能

二、Runloop的模式和状态

  1. 一个Runloop对应一条线程 。[1]
  1. 一个Runloop里面可以有多个mode,每一个Mode又可以包含多个mode item
  2. source/timer/observer被统称为mode item,不同的modemode item互不影响。
  3. 同一个时刻,RunLoop只能是在一个mode上面的运行。如果需要切换mode,只能是退出currentMode,切换到指定的mode
image

1、RunLoop的模式

总共是有五种CFRunLoopMode:(前2种常见的及后3种不常见的、系统的)

  • kCFRunLoopDefaultMode:默认模式,主线程是在这个运行模式下运行
  • UITrackingRunLoopMode:界面跟踪mode,用于ScrollView追踪触摸滑动,保证界面滑动时不受其他mode影响(当一旦滚动屏幕,就会自动切换到这个模式)
  • UIInitializationRunLoopMode:在刚启动App时第进入的第一个mode,启动完成后就不再使用
  • GSEventReceiveRunLoopMode:接受系统内部事件,通常用不到
  • kCFRunLoopCommonModes:伪mode,若干个mode的集合,是同步Source/Timer/Observer到多个mode中的一种解决方案

2、RunLoop的状态

typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
    kCFRunLoopEntry         = (1UL << 0), // 即将进入Loop
    kCFRunLoopBeforeTimers  = (1UL << 1), // 即将处理 Timer
    kCFRunLoopBeforeSources = (1UL << 2), // 即将处理 Source
    kCFRunLoopBeforeWaiting = (1UL << 5), // 即将进入休眠
    kCFRunLoopAfterWaiting  = (1UL << 6), // 刚从休眠中唤醒
    kCFRunLoopExit          = (1UL << 7), // 即将退出Loop
};

三、RunLoop的运行逻辑

运行逻辑

总结成一句话就是:RunLoop的运行逻辑就是do-while循环下运用观察者模式(或者说是消息发送),根据7种状态的变化,处理事件输入源和定时器。


四、面试题

1、什么是RunLoop?

  • 从字面上理解,RunLoop是个运行循环。
  • 其实它内部就是do-while循环,在这个循环内部不断的处理各种任务(比如Source\Timer\Observer)
  • 一个线程对应一个RunLoop,主线程的RunLoop默认已经启动,子线程的RunLoop需要手动启动(调用run方法)
    RunLoop只能选择一个mode启动,如果当前mode中没有任何Soure\Timer\Observer,那么就直接退出RunLoop

2、在开发中如何使用RunLoop?什么应用场景?

场景一:解决NSTimer在ScrollView滑动的时候失效的问题

static int count = 0;
[NSTimer scheduledTimerWithTimeInterval:1 repeats:YES >block:^(NSTimer * _Nonnull timer) {
   NSLog(@"count == %d",count++);
}];

原因
NSTimerRunLoopmodeNSDefaultRunLoopMode中的,当滑动的时候RunLoop会切换到UITrackingRunLoopMode,所以NSTimer会失效。

解决
Timer添加到NSRunLoopCommonModes模式下面

NSTimer *timer = [NSTimer timerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
   NSLog(@"count == %d",count++);
}];
   
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

  1. 线程和runloop是一一对应的关系,内部是一个字典,key为线程,value为runloop

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