从接触iOS到现在也有将近两年了,对iOS中的RunLoop也有了一定的认识,下面讲讲个人对RunLoop的理解

  初识RunLoop

RunLoops是与线程相关联的基础部分,一个Run Loop就是事件处理循环,他是用来调度和协调接收到的事件处理。使用RunLoop的目的,就是使的线程有工作需要做的时候忙碌起来,当没事做的时候,又可以使得线程休眠。

我们一般程序就是执行一个线程,是一条直线.有起点终点.而runloop就是一直在线程上面画圆圈,一直在跑圈,除非切断否则一直在运行。网上说的比喻很好,直线就像昙花一现一样,圆就像OS,一直运行直到你关机为止。

RunLoop资料

    苹果官方文档:

https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html

CFRunLoopRef是开源的:

http://opensource.apple.com/source/CF/CF-1151.16/

RunLoop对象

iOS中有两套API来访问和使用RunLoop

  • Foundation框架 --> NSRunLoop
  • Core Foundation框架 -->CFRunLoopRef

NSRunLoop和CFRunLoopRef都代表着RunLoop对象
NSRunLoop是基于CFRunLoopRef的一层OC包装, 所以要了解RunLoop内部结构, 需要多研究CFRunLoopRef层面的API(Core Foundation层面)

RunLoop与线程

  • 每条线程都有唯一的一个与之对应的RunLoop对象(如果我也想开一个子线成,并且让线程不死,则子线程开一个RunLoop)
  • 主线程的RunLoop已经自动创建好了,子线程的RunLoop需要主动创建
  • RunLoop在第一次获取时创建,在线程结束时销毁

获得RunLoop对象

  • Foundation
[NSRunLoop currentRunLoop]; // 获得当前线程的RunLoop对象
[NSRunLoop mainRunLoop]; // 获得主线程的RunLoop对象
  • Core Foundation
CFRunLoopGetCurrent(); // 获得当前线程的RunLoop对象
CFRunLoopGetMain(); // 获得主线程的RunLoop对象

如果在主线程中: 当前线程的RunLoop对象和主线程的RunLoop对象取得的是相同的。

CFRunLoopSourceRef

  • CFRunLoopModeRef代表RunLoop的运行模式
  • 一个RunLoop包含若干个Mode,每个Mode又包含若干个Source/Timer/Observer
  • 每次RunLoop启动时,只能指定其中一个 Mode,这个Mode被称作 CurrentMode(可以获取到[NSRunLoop currentRunLoop].currentMode)
  • 如果需要切换Mode,只能退出Loop再重新指定一个Mode进入(因为RunLoop是一个运行循环, 一直在跑圈, 换另一个模式,必须先退出, 然后按照另一个模式跑圈)
  • 这样做主要是为了分隔开不同组的Source/Timer/Observer,让其互不影响(切换模式是为了,让它按照另一个模式的Source,Timer,Observer来跑圈, 互不影响)

RunLoop 启动必须要传入一个模式,RunLoop有多个模式, 但是每次只能运行一种模式

   

     RunLoop定义两个Version的Source

  • Source0:处理App内部事件,App自己负责管理(触发),如UIEvent,CFSocket
  • Source1:由RunLoop和内核管理,Mach port驱动 如CFMach、CFMessage

CFRunLoopObserverRef

      向内部报告RunLoop当前状态的更改 CAAnimation

可以监听的时间点如下几点:

   

RunLoopObserver 与 Autorelease Pool

UIKit通过RunLoopObserver在RunLoop两次Sleep间对AutoreleasePool进行pop和push,将这次Loop中产生的Autorelease对象释放。(好像swift中没有关于释放的问题)

  

CFRunLoopModeRef

RunLoop在同一时段只能且必须在一种特定Mode下Run
更换Mode时, 需要暂停当前的Loop,然后重启新的Loop NSDefalutRunLoopMode      默认状态.空闲状态
UITrackingRunLoopMode     滑动ScrollView
UIInitializationRunLoopMode    私有,App启动时
NSRunLoopCommonModes     默认包括上面第一和第二

  

CFRunLoopTimerRef

  • CFRunLoopTimerRef是基于时间的触发器(基本上说的就是NSTimer), 一个模式下可以有多个Timer(Arrar中存放)
 /**
* 这个方法内部实现是: 创建timer,添加到RunLoop中的默认的Mode中,RunLoop启动这个mode,取出这个mode中timer来用
*/
[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(run) userInfo:nil repeats:YES]; /**
* 上面的代码等同于下面的
*/
// 创建Timer
NSTimer *timer = [NSTimer timerWithTimeInterval:0.5 target:self selector:@selector(run) userInfo:nil repeats:YES]; // 定时器只运行在 NSDefaultRunLoopMode 模式下, 一旦RunLoop进入其他模式,这个定时器就不会工作
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; // 如果拖动时, 我们将定时器添打上这个NSRunLoopCommonModes的标记
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; NSLog(@"-----------%@", [NSRunLoop currentRunLoop]);
/**
* 定时器会跑在标记为common modes的模式下(这个模式只是个标记)
* RunLoop会寻找带有common标签的模式,有这个标签的,都可以跑
* 打印当前的RunLoop信息输出为:(有common modes标签的有两个,UITrackingRunLoopMode和kCFRunLoopDefaultMode),所以定时器可以在这两个模式下跑, RunLoop只会运行一种模式 common modes = <CFBasicHash 0x7fb8b2700490 [0x10ec6ba40]>{type = mutable set, count = 2,
entries =>
0 : <CFString 0x10fba2210 [0x10ec6ba40]>{contents = "UITrackingRunLoopMode"}
2 : <CFString 0x10ec8c5e0 [0x10ec6ba40]>{contents = "kCFRunLoopDefaultMode"}
}
*/

 AFNetWorking 中创建RunLoop

     

 [[NSThread currentThread] setName:@"AFNetworking"];
NSRunLoop *runloop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefalutRunLoopMode]//一直活着
[runLoop run];

这在处理网络响应是一个很好的方法

UITrackingRunLoopMode 与 NSTimer

// 默认情况下NSTimer被加入NSDefalutRunLoopMode
//如果想NSTimer受到组件或者动画影响 添加到NSRunLoopCommonModes [[NSRunLoop currentRunLoop]addTimer:timer...forMode:NSRunLoopCommonModes];

RunLoop的处理逻辑是什么呢?

每次运行run loop,你线程的run loop对会自动处理之前未处理的消息,并通知相关的观察者。具体的顺序如下:

  1. 通知观察者run loop已经启动
  2. 通知观察者任何即将要开始的定时器
  3. 通知观察者任何即将启动的非基于端口的源
  4. 启动任何准备好的非基于端口的源
  5. 如果基于端口的源准备好并处于等待状态,立即启动;并进入步骤9。
  6. 通知观察者线程进入休眠
  7. 将线程置于休眠直到任一下面的事件发生:
    • 某一事件到达基于端口的源
    • 定时器启动
    • Run loop设置的时间已经超时
    • run loop被显式唤醒
  8. 通知观察者线程将被唤醒。
  9. 处理未处理的事件
    • 如果用户定义的定时器启动,处理定时器事件并重启run loop。进入步骤2
    • 如果输入源启动,传递相应的消息
    • 如果run loop被显式唤醒而且时间还没超时,重启run loop。进入步骤2
  10. 通知观察者run loop结束。
好的文章都是值得反复看的,我们在不同的阶段来相同的文章或资料都能有不同的收获,
提高自己对知识的理解,声明一下:最好是自己理解后再总结一次,不要一味的收藏,
每个程序员都有着成为大牛的潜质,只在是否努力。加油 技术宅们!

  

   


  

iOS开发中对RunLoop的个人心得的更多相关文章

  1. 总结iOS开发中的断点续传那些事儿

    前言 断点续传概述 断点续传就是从文件赏赐中断的地方重新开始下载或者上传数据,而不是从头文件开始.当下载大文件的时候,如果没有实现断点续传功能,那么每次出现异常或者用户主动的暂停,都会从头下载,这样很 ...

  2. fir.im Weekly - iOS开发中的Git流程

    本期 fir.im Weekly 收集了微博上的热转资源,包含 Android.iOS 开发工具.源码等好用的轮子,还有一些 APP 设计的 Tips,希望对你有用. 精仿知乎日报 iOS 端 @我偏 ...

  3. iOS开发中静态库之".framework静态库"的制作及使用篇

    iOS开发中静态库之".framework静态库"的制作及使用篇 .framework静态库支持OC和swift .a静态库如何制作可参照上一篇: iOS开发中静态库之" ...

  4. iOS开发中静态库制作 之.a静态库制作及使用篇

    iOS开发中静态库之".a静态库"的制作及使用篇 一.库的简介 1.什么是库? 库是程序代码的集合,是共享程序代码的一种方式 2.库的类型? 根据源代码的公开情况,库可以分为2种类 ...

  5. ios开发中的小技巧

    在这里总结一些iOS开发中的小技巧,能大大方便我们的开发,持续更新. UITableView的Group样式下顶部空白处理 //分组列表头部空白处理 UIView *view = [[UIViewal ...

  6. IOS 开发中 Whose view is not in the window hierarchy 错误的解决办法

    在 IOS 开发当中经常碰到 whose view is not in the window hierarchy 的错误,该错误简单的说,是由于 "ViewController" ...

  7. [转]iOS开发中的火星坐标系及各种坐标系转换算法

     iOS开发中的火星坐标系及各种坐标系转换算法 源:https://my.oschina.net/u/2607703/blog/619183   其原理是这样的:保密局开发了一个系统,能将实际的坐标转 ...

  8. iOS开发中常见问题集锦

    在iOS开发中,会出现各种各样的问题.今天,就把这些常见的问题以及各位大牛的解决方案汇总下,方便以后查阅: 常见错误: 1. linker command failed with exit code ...

  9. iOS开发中获取WiFi相关信息

    iOS 开发中难免会遇到很多与网络方面的判断,这里做个汇总,大多可能是与WiFi相关的. 1.Ping域名.Ping某IP 有 时候可能会遇到ping 某个域名或者ip通不通,再做下一步操作.这里的p ...

随机推荐

  1. git将已经同步的某类文件加入忽略列表并同步

    1> 添加.gitignore文件到根目录,并在文件中写入忽略文件的类型或具体路径,比如: *.zip 和 /RSGIS/SnowEffect/SnowEffect.pro.user 2> ...

  2. 在linux中配置安装telnet服务

    Telnet 是一种流行的用于通过 Internet 登录到远程计算机的协议.Telnet 服务器软件包为远程登录主机提供了支持.要通过 Telnet 协议与另一台主机通讯,您可以使用名称或 Inte ...

  3. sqlldr

    1.字符集 sqlldr可以指定读取的文件的字符集,如果数据库为gbk,读取的文件为utf-8,这个时候就需要指定字符集 load data CHARACTERSET 'UTF8' 2.sqlldr导 ...

  4. Loadrunner---解决乱码问题

    在使用Loadrunner录制和回放时有时候会因为乱码问题报错,且让我们很难定位出脚本问题所在.此事我们做一下分析loadrunner为什么会出现乱码这种情况呢? 1.乱码产生的原因 1)loadru ...

  5. idea 小技巧

    idea tomcat.debug显示如下 2.项目中java文件导入一个包下的多个文件时,idea默认超过3个时会用*代替.如果不想这样,操作如下 3.java类实现Serializable,自动生 ...

  6. C#实现获取文本文件的编码的一个类(区分GB2312和UTF8)-来自转载收集

    using System; using System.IO; using System.Text; /// <summary> /// FileEncoding 的摘要说明 /// < ...

  7. equals标准写法

    @Overridepublic boolean equals(Object obj) { //为了提高效率 if(this == obj){ return true; } //为了提供程序的健壮性 / ...

  8. django修改admin密码

    python manage.py shell 然后获取你的用户名,并且重设密码:from django.contrib.auth.models import User user = User.obje ...

  9. Hello mybatis

    idea玩mybatis,终于搞出个hello mybatis.记录下过程,备忘. 1.person表 CREATE TABLE `person` ( `id` ) NOT NULL AUTO_INC ...

  10. Theme皮肤文件(json解析、多文件管理)

    一  官方教程 http://developer.egret.com/cn/github/egret-docs/extension/EUI/skin/theme/index.html 二 thm主题文 ...