• 介绍

  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 消息循环的更多相关文章

  1. ios - 图片自动轮播定时器(NSTimer)以及消息循环模式简介

    本文只是演示如何设置图片轮播的定时器. 创建全局变量NSTimer 程序启动后就开始轮播图片,所以在- (void)viewDidLoad中就启动定时器. 将定时器放入消息循环池中.- (void)v ...

  2. iOS Runloop理解

    一.RunLoop的定义 当有持续的异步任务需求时,我们会创建一个独立的生命周期可控的线程.RunLoop就是控制线程生命周期并接收事件进行处理的机制. RunLoop是iOS事件响应与任务处理最核心 ...

  3. iOS RunLoop详解

    1. RunLoop简介 1.1 什么是RUnLoop 可以理解为字面的意思:Run表示运行,Loop表示循环.结合在一起就是运行的循环.通常叫做运行循环. RunLoop实际上是一个对象,这个对象在 ...

  4. Android Handler 消息循环机制

    前言 一问起Android应用程序的入口,很多人会说是Activity中的onCreate方法,也有人说是ActivityThread中的静态main方法.因为Java虚拟机在运行的时候会自动加载指定 ...

  5. iOS 10 消息推送(UserNotifications)秘籍总结(一)

    前言 之前说会单独整理消息通知的内容,但是因为工(就)作(是)的(很)事(懒)没有更新文章,违背了自己的学习的初衷.因为互联网一定要有危机意识,说不定眼一睁,我们就out丢了饭碗. 图片来源网络.jp ...

  6. Chromium on Android: Android在系统Chromium为了实现主消息循环分析

    总结:刚开始接触一个Chromium on Android时间.很好奇Chromium主消息循环是如何整合Android应用. 为Android计划,一旦启动,主线程将具有Java消息层循环处理系统事 ...

  7. iOS中消息传递方式

    iOS中消息传递方式 在iOS中有很多种消息传递方式,这里先简单介绍一下各种消息传递方式. 1.通知:在iOS中由通知中心进行消息接收和消息广播,是一种一对多的消息传递方式. NSNotificati ...

  8. iOS开发-消息初认识

    一.消息循环(runLoop)的作用 1,防止程序退出, 2,接受事件 3,如果没有事件,让程序自动休眠   二.消息源    1, 输入源:键盘.鼠标.NSBoard.NSPort    2,定时源 ...

  9. 分分钟搞定IOS远程消息推送

    一.引言 IOS中消息的推送有两种方式,分别是本地推送和远程推送,本地推送在http://my.oschina.net/u/2340880/blog/405491这篇博客中有详细的介绍,这里主要讨论远 ...

随机推荐

  1. 【旧文章搬运】KeUserModeCallback用法详解

    原文发表于百度空间及看雪论坛,2010-01-10 看雪论坛地址:https://bbs.pediy.com/thread-104918.htm  代码及附件可到这里下载=============== ...

  2. Java字符串理解

    1. 字符串基本知识 用java.lang.String类的对象表示字符串 字符串类型不是基本类型, 而是引用类型(类似于数组和对象) Java基于Unicode字符集 2. 字符串创建 public ...

  3. Hadoop 源代码组织结构

    Hadoop 2.X 包括 编译好的可以直接部署的文件hadoop-{VERSION}.tar.gz; 还有源代码文件hadoop-{VERSION}-src.tar.gz , 需要 Maven 编译 ...

  4. 【Hadoop】MapReduce笔记(四):MapReduce优化策略总结

    Cloudera 提供给客户的服务内容之一就是调整和优化MapReduce job执行性能.MapReduce和HDFS组成一个复杂的分布式系统,并且它们运行着各式各样用户的代码,这样导致没有一个快速 ...

  5. 【eclipse插件开发实战】Eclipse插件开发3——OSGi、RCP

    Eclipse插件开发实战3--OSGi.RCP 一.OSGi 1. 什么是OSGi框架 OSGi(Open Service Gateway Initiative)框架是运行在JavaVM环境里的服务 ...

  6. 原创|高逼格企业级MySQL数据库备份方案,原来是这样....

    很多人,这里说的是运维工程师们,一提到写某某方案,很是头疼.不是上某度一统搜索,就是同样一句话在N个群全部群发一遍:“有没有某某方案,可以共享一下的吗??求助,各位大佬们”,估计十有八九,全部石沉大海 ...

  7. 在 beforeSend中设置ajax请求的Content-type

    $.ajaxSetup({        beforeSend: function (xhr, settings) {            if (settings.type == "PO ...

  8. Lightoj1012【DFS】

    题意: 输出和' @ '相连有多少个' . '包括' @ ',' # '代表墙不能走: 思路: 基础DFS,找到起点,然后跑一下DFS就好了: #include<cstdio> #incl ...

  9. 如何有效提升Unity Gear VR游戏性能

    http://www.vr186.com/vr_news/vr_technical_area/1093.html 好的,所以你决定用 Unity 来做一个 VR 游戏,并选定了三星 Gear vr 为 ...

  10. uoj#268. 【清华集训2016】数据交互(动态dp+堆)

    传送门 动态dp我好像还真没咋做过--通过一个上午的努力光荣的获得了所有AC的人里面的倒数rk3 首先有一个我一点也不觉得显然的定理,如果两条路径相交,那么一定有一条路径的\(LCA\)在另一条路径上 ...