iOS Runloop 消息循环
- 介绍
Runloop是一种事件监听循环,可以理解成一个while死循环,监听到事件就起来,没有就休息。
Runloop可以在不同模式下进行切换,iOS有五种模式,其中UIInitializationRunLoopModel应用程序启动时会使用,启动完成后将不再使用;GSEventReceiveRunLoopMode这个是接受系统内部的Model,通常做不到。还有UITrackingRunLoopMode、NSDefaultRunLoopMode、NSRunLoopCommonModes三种模式是我们通常用到的,下文中会详细讲解,其中NSRunLoopCommonModes是一个占位符,NSDefaultRunLoopMode和UITrackingRunLoopMode都会绑定这个占位符。
- Runloop
- 1.1 字面意思
a 运行循环
b 跑圈
- 1.2 基本作用(作用重大)
(1) 保持程序的持续运行(ios程序为什么能一直活着不会死)
(2) 处理app中的各种事件(比如触摸事件、定时器事件【NSTimer】、selector事件【选择器·performSelector···】)
(3) 节省CPU资源,提高程序性能,有事情就做事情,没事情就休息
- 1.3 重要说明
()如果没有Runloop,那么程序一启动就会退出,什么事情都做不了。
()如果有了Runloop,那么相当于在内部有一个死循环,能够保证程序的持续运行
()main函数中的Runloop
()在UIApplication函数内部就启动了一个Runloop,函数返回一个int类型的值
()这个默认启动的Runloop是跟主线程相关联的
- 1.4 Runloop对象
()在iOS开发中有两套api来访问Runloop
a.foundation框架【NSRunloop】
b.core foundation框架【CFRunloopRef】
()NSRunLoop和CFRunLoopRef都代表着RunLoop对象,它们是等价的,可以互相转换
()NSRunLoop是基于CFRunLoopRef的一层OC包装,所以要了解RunLoop内部结构,需要多研究CFRunLoopRef层面的API(Core Foundation层面)
- 1.5 Runloop参考资料
()苹果官方文档:
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html
()CFRunLoopRef开源代码下载地址:
http://opensource.apple.com/source/CF/CF-1151.16/
- 1.6 Runloop与线程
()Runloop和线程的关系:一个Runloop对应着一条唯一的线程
问题:如何让子线程不死
回答:给这条子线程开启一个Runloop
()Runloop的创建:主线程Runloop已经创建好了,子线程的runloop需要手动创建
()Runloop的生命周期:在第一次获取时创建,在线程结束时销毁
- 1.7 获得Runloop对象
()获得当前Runloop对象
a. NSRunloop
NSRunLoop * runloop1 = [NSRunLoop currentRunLoop];
b.CFRunLoopRef
CFRunLoopRef runloop2 = CFRunLoopGetCurrent();
()拿到当前应用程序的主Runloop(主线程对应的Runloop)
a.NSRunloop
NSRunLoop * runloop1 = [NSRunLoop mainRunLoop];
b.CFRunLoopRef
CFRunLoopRef runloop2 = CFRunLoopGetMain();
()注意点:开一个子线程创建runloop,不是通过alloc init方法创建,而是直接通过调用currentRunLoop方法来创建,它本身是一个懒加载的。
()在子线程中,如果不主动获取Runloop的话,那么子线程内部是不会创建Runloop的。可以下载CFRunloopRef的源码,搜索_CFRunloopGet0,查看代码。
()Runloop对象是利用字典来进行存储,而且key是对应的线程Value为该线程对应的Runloop。
- 1.8 Runloop相关类
()Runloop运行原理图
()五个相关的类
a.CFRunloopRef
b.CFRunloopModeRef【Runloop的运行模式】
c.CFRunloopSourceRef【Runloop要处理的事件源】
d.CFRunloopTimerRef【Timer事件】
e.CFRunloopObserverRef【Runloop的观察者(监听者)】
()Runloop和相关类之间的关系图
()Runloop要想跑起来,它的内部必须要有一个mode,这个mode里面必须有source\observer\timer,至少要有其中的一个。
- CFRunloopModeRef
()CFRunloopModeRef代表着Runloop的运行模式
()一个Runloop中可以有多个mode,一个mode里面又可以有多个source\observer\timer等等
()每次runloop启动的时候,只能指定一个mode,这个mode被称为该Runloop的当前mode
()如果需要切换mode,只能先退出当前Runloop,再重新指定一个mode进入
()这样做主要是为了分割不同组的定时器等,让他们相互之间不受影响
()系统默认注册了5个mode
a.kCFRunLoopDefaultMode:App的默认Mode,通常主线程是在这个Mode下运行
b.UITrackingRunLoopMode:界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响
c.UIInitializationRunLoopMode: 在刚启动 App 时第进入的第一个 Mode,启动完成后就不再使用
d.GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,通常用不到
e.kCFRunLoopCommonModes: 这是一个占位用的Mode,不是一种真正的Mode
- Runloop 其它三种模式
→ UITrackingRunLoopMode : (优先切换!!)这个模式就是当UI事件交互的时候Runloop切换到的模式!!!
场景:这一模式优先级最高,当UI事件交互的时候,都会优先切换到这一模式。
测试代码如下:
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval: repeats:YES block:^(NSTimer * _Nonnull timer) {
NSLog(@"current Runloop = %@", [NSRunLoop currentRunLoop].currentMode);
}];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
结果:
current Runloop = kCFRunLoopDefaultMode //执行时默认此默认模式
current Runloop = UITrackingRunLoopMode //当滑动页面的UITextView的时,优先自动切换到此模式。
current Runloop = kCFRunLoopDefaultMode // 当不对页面的UITextView的操作时,重新恢复到默认模式。
→ NSDefaultRunLoopMode :Runloop的默认模式!只要有事件就处理!
场景:默认模式,只要有事件就会自动切换到此模式。
测试代码如下:
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval: repeats:YES block:^(NSTimer * _Nonnull timer) {
NSLog(@"current Runloop = %@", [NSRunLoop currentRunLoop].currentMode);
}];
结果:
current Runloop = kCFRunLoopDefaultMode //程序启动后默认进入此模式
→ NSRunLoopCommonModes :占位符!!(在默认下和UITrackingRunLoopMode下!)
场景:这个主要用在添加一个NSTimer到RunLoop中。是一个tag,本质上不是一个Mode,默认NSDefaultRunLoopMode和 NSTrackingRunLoopMode都绑定这个tag。
实例代码:
static int i = ;
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval: repeats:YES block:^(NSTimer * _Nonnull timer) {
lable.text = [NSString stringWithFormat:@"始终当前显示的索引:%zi", ++i];
}];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
特殊说明:
1、一个线程对象就对应一个RunLoop对象。创建后,默认启动该MainRunLoop对象。其内部是一个do-while循环。
2、主线程默认会启动一个Runloop,子线程不会自动启动Runloop需要我们手动启动。见以下代码说明。
static int i = ;
dispatch_queue_t queue = dispatch_queue_create(, );
//开启一个子线程
dispatch_async(queue, ^{
NSTimer *timer = [NSTimer timerWithTimeInterval: repeats:YES block:^(NSTimer * _Nonnull timer) {
NSLog(@"display result = %zi, %@", ++i, [NSRunLoop currentRunLoop].currentMode);
}];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
[[NSRunLoop currentRunLoop] run]; //手动启动Runloop
});
- 图解说明

- Runloop 总结
可以看出,RunLoop被开启的线程会一直存在。因为在没有事件发生的时候处于休眠状态,有事件发生的时候处于工作状态。以此来节约CPU资源。这样就可以让一个线程成为常驻线程,也就是说该线程一直存在。
RunLoop是iOS事件响应与任务处理最核心的机制,它贯穿iOS整个系统。
RunLoop是一种事件运行循环机制,是保持应用程序持续运行的一种机制。正是由于该机制的存在,应用程序才能在没有事件发生的时候处于休眠状态,有事件发生的时候处于工作状态。以此来节约CPU资源。这也是它的一大特点。
NSRunLoop是Cocoa框架中的类,与之对应的,在Core Foundation中是CFRunLoopRef类。两者的区别是前者不是线程安全的,后者是线程安全的,且两者可以相互转化。
RunLoop和线程的关系:
RunLoop是用来管理线程的,每个线程对应一个RunLoop对象。我们不可以去创建当前线程的RunLoop对象,但是我们可以去获取当前线程的RunLoop。RunLoop就是来监听该线程有无事件发生,如果有就工作,如果没有就休眠。
主线程的RunLoop对象默认开启,其他线程默认不开启。
RunLoop与AutoreleasePool;
RunLoop处理的事件类型;
RunLoop的运行模式mode;
iOS Runloop 消息循环的更多相关文章
- ios - 图片自动轮播定时器(NSTimer)以及消息循环模式简介
本文只是演示如何设置图片轮播的定时器. 创建全局变量NSTimer 程序启动后就开始轮播图片,所以在- (void)viewDidLoad中就启动定时器. 将定时器放入消息循环池中.- (void)v ...
- iOS Runloop理解
一.RunLoop的定义 当有持续的异步任务需求时,我们会创建一个独立的生命周期可控的线程.RunLoop就是控制线程生命周期并接收事件进行处理的机制. RunLoop是iOS事件响应与任务处理最核心 ...
- iOS RunLoop详解
1. RunLoop简介 1.1 什么是RUnLoop 可以理解为字面的意思:Run表示运行,Loop表示循环.结合在一起就是运行的循环.通常叫做运行循环. RunLoop实际上是一个对象,这个对象在 ...
- Android Handler 消息循环机制
前言 一问起Android应用程序的入口,很多人会说是Activity中的onCreate方法,也有人说是ActivityThread中的静态main方法.因为Java虚拟机在运行的时候会自动加载指定 ...
- iOS 10 消息推送(UserNotifications)秘籍总结(一)
前言 之前说会单独整理消息通知的内容,但是因为工(就)作(是)的(很)事(懒)没有更新文章,违背了自己的学习的初衷.因为互联网一定要有危机意识,说不定眼一睁,我们就out丢了饭碗. 图片来源网络.jp ...
- Chromium on Android: Android在系统Chromium为了实现主消息循环分析
总结:刚开始接触一个Chromium on Android时间.很好奇Chromium主消息循环是如何整合Android应用. 为Android计划,一旦启动,主线程将具有Java消息层循环处理系统事 ...
- iOS中消息传递方式
iOS中消息传递方式 在iOS中有很多种消息传递方式,这里先简单介绍一下各种消息传递方式. 1.通知:在iOS中由通知中心进行消息接收和消息广播,是一种一对多的消息传递方式. NSNotificati ...
- iOS开发-消息初认识
一.消息循环(runLoop)的作用 1,防止程序退出, 2,接受事件 3,如果没有事件,让程序自动休眠 二.消息源 1, 输入源:键盘.鼠标.NSBoard.NSPort 2,定时源 ...
- 分分钟搞定IOS远程消息推送
一.引言 IOS中消息的推送有两种方式,分别是本地推送和远程推送,本地推送在http://my.oschina.net/u/2340880/blog/405491这篇博客中有详细的介绍,这里主要讨论远 ...
随机推荐
- 移植最新版libmemcached到VC++的艰苦历程和经验总结(下)
结果如何呢?我的VC++测试用例还是不能调用该接口的接口方法,只是这次的报错方式有所改变,提示是每个C/C++程序员最不愿意看到的“内存地址访问违规”,这一次我确实被郁闷了,这是为什么呢? 五.gcc ...
- spellchecker inspection helps locate typeos and misspelling in your code, comments and literals, and fix them in one click
项目layout文件中出现 spellchecker inspection helps locate typos and misspelling in your code, comments and ...
- OpenFileDialog无法弹出的解决方法
今天在写一个socket通信的winform小程序,由于socket的receive方法会阻塞线程,所以就使用了多线程解决.但在新建的线程中创建OpenFileDialog并调用其ShowDialog ...
- js事件触发器fireEvent和dispatchEvent
转自:https://www.cnblogs.com/tiger95/p/6962059.html 事件触发器就是用来触发某个元素下的某个事件,IE下fireEvent方法,高级浏览器(chrome, ...
- 重载和const形参的学习心得
在C++ primer 5th中,第6章的练习6.39(a)中,关于重载和const形参的学习心得. 练习6.39:说明在下面的每组声明中第二条声明语句是何含义.如果有非法的声明,请指出来. (a) ...
- opencv Mat.at
opencv c++ mat获取像素及像素赋值 For accessing pixel's channel value : ; i < image.cols; i++) { ; j < i ...
- 使用httpClient下载网页
HttpCore 对HTTP协议客户端编程做了一些基本的封装.例如,格式化请求头和解析响应头.LineF ormatter用来格式化请求头信息,而实际的实现在BasicLineF ormatter 上 ...
- 3.7-3.10 Hive 企业使用优化1
一.Fetch Task 在执行hive代码的时候,一条简单的命令大部分都会转换成为mr代码在后台执行, 但是有时候我们仅仅只是想获取一部分数据而已,仅仅是获取数据,还需要转化成为mr去执行吗? 那个 ...
- mysql 、redis的区别
我们知道,mysql是持久化存储,存放在磁盘里面,检索的话,会涉及到一定的IO,为了解决这个瓶颈,于是出现了缓存,比如现在用的最多的 memcached(简称mc).首先,用户访问mc,如果未命中,就 ...
- Makefile研究(三) —— 实际应用
转自:http://blog.csdn.net/jundic/article/details/17886637 前面讲了Makefile 的简单语法和简单的应用模板,但在实际项目应用中比这个肯定复杂很 ...