iOS开发中对RunLoop的个人心得
从接触iOS到现在也有将近两年了,对iOS中的RunLoop也有了一定的认识,下面讲讲个人对RunLoop的理解。
初识RunLoop
RunLoops是与线程相关联的基础部分,一个Run Loop就是事件处理循环,他是用来调度和协调接收到的事件处理。使用RunLoop的目的,就是使的线程有工作需要做的时候忙碌起来,当没事做的时候,又可以使得线程休眠。
我们一般程序就是执行一个线程,是一条直线.有起点终点.而runloop就是一直在线程上面画圆圈,一直在跑圈,除非切断否则一直在运行。网上说的比喻很好,直线就像昙花一现一样,圆就像OS,一直运行直到你关机为止。
RunLoop资料
苹果官方文档:
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对会自动处理之前未处理的消息,并通知相关的观察者。具体的顺序如下:
- 通知观察者run loop已经启动
- 通知观察者任何即将要开始的定时器
- 通知观察者任何即将启动的非基于端口的源
- 启动任何准备好的非基于端口的源
- 如果基于端口的源准备好并处于等待状态,立即启动;并进入步骤9。
- 通知观察者线程进入休眠
- 将线程置于休眠直到任一下面的事件发生:
- 某一事件到达基于端口的源
- 定时器启动
- Run loop设置的时间已经超时
- run loop被显式唤醒
- 通知观察者线程将被唤醒。
- 处理未处理的事件
- 如果用户定义的定时器启动,处理定时器事件并重启run loop。进入步骤2
- 如果输入源启动,传递相应的消息
- 如果run loop被显式唤醒而且时间还没超时,重启run loop。进入步骤2
- 通知观察者run loop结束。
好的文章都是值得反复看的,我们在不同的阶段来相同的文章或资料都能有不同的收获,
提高自己对知识的理解,声明一下:最好是自己理解后再总结一次,不要一味的收藏,
每个程序员都有着成为大牛的潜质,只在是否努力。加油 技术宅们!
iOS开发中对RunLoop的个人心得的更多相关文章
- 总结iOS开发中的断点续传那些事儿
前言 断点续传概述 断点续传就是从文件赏赐中断的地方重新开始下载或者上传数据,而不是从头文件开始.当下载大文件的时候,如果没有实现断点续传功能,那么每次出现异常或者用户主动的暂停,都会从头下载,这样很 ...
- fir.im Weekly - iOS开发中的Git流程
本期 fir.im Weekly 收集了微博上的热转资源,包含 Android.iOS 开发工具.源码等好用的轮子,还有一些 APP 设计的 Tips,希望对你有用. 精仿知乎日报 iOS 端 @我偏 ...
- iOS开发中静态库之".framework静态库"的制作及使用篇
iOS开发中静态库之".framework静态库"的制作及使用篇 .framework静态库支持OC和swift .a静态库如何制作可参照上一篇: iOS开发中静态库之" ...
- iOS开发中静态库制作 之.a静态库制作及使用篇
iOS开发中静态库之".a静态库"的制作及使用篇 一.库的简介 1.什么是库? 库是程序代码的集合,是共享程序代码的一种方式 2.库的类型? 根据源代码的公开情况,库可以分为2种类 ...
- ios开发中的小技巧
在这里总结一些iOS开发中的小技巧,能大大方便我们的开发,持续更新. UITableView的Group样式下顶部空白处理 //分组列表头部空白处理 UIView *view = [[UIViewal ...
- IOS 开发中 Whose view is not in the window hierarchy 错误的解决办法
在 IOS 开发当中经常碰到 whose view is not in the window hierarchy 的错误,该错误简单的说,是由于 "ViewController" ...
- [转]iOS开发中的火星坐标系及各种坐标系转换算法
iOS开发中的火星坐标系及各种坐标系转换算法 源:https://my.oschina.net/u/2607703/blog/619183 其原理是这样的:保密局开发了一个系统,能将实际的坐标转 ...
- iOS开发中常见问题集锦
在iOS开发中,会出现各种各样的问题.今天,就把这些常见的问题以及各位大牛的解决方案汇总下,方便以后查阅: 常见错误: 1. linker command failed with exit code ...
- iOS开发中获取WiFi相关信息
iOS 开发中难免会遇到很多与网络方面的判断,这里做个汇总,大多可能是与WiFi相关的. 1.Ping域名.Ping某IP 有 时候可能会遇到ping 某个域名或者ip通不通,再做下一步操作.这里的p ...
随机推荐
- 高斯模糊算法的 C++ 实现
2008 年在一个 PS 讨论群里,有网友不解 Photoshop 的高斯模糊中的半径是什么含义,因此当时我写了这篇文章: 对Photoshop高斯模糊滤镜的算法总结: 在那篇文章中,主要讲解了高斯模 ...
- 利用SQL注入漏洞登录后台的实现方法
利用SQL注入漏洞登录后台的实现方法 作者: 字体:[增加 减小] 类型:转载 时间:2012-01-12我要评论 工作需要,得好好补习下关于WEB安全方面的相关知识,故撰此文,权当总结,别无它意.读 ...
- Delphi DateUtils时间单元
Uses DateUtils //时间单元,非常有用. 记得引用这个单元,不然不能用. CompareDate 比较两个日期时间值日期部分的大小 CompareDateTime 比较两个日期时间值的大 ...
- 如何在winform或者wpf里面打开浏览器并设置宽高位置
需要SHDocVw.dll 文件或AxSHDocVw.dll 文件,.net默认是没有的,先生产这两个文件,请在Visual Studio 命令提示符下运行下面的命令: aximp %WINDIR%\ ...
- Jsoup使用随记
这段时间工作比较空闲,在网上找资料学习的时候看到数据抓取这一块,来了兴趣 用jsoup实现数据抓取着实方便,唯一美中不足的是官方API是英文版的,对我这样英语水平不好的程序员来说着实困扰,只能一点点的 ...
- 【原创】loadrunner12.53 录制脚本时 打不开网页或者打开网页慢?
问题描述: 之前刚装12.5版本时候,用 WebTours测试过,应用程序选择自己本地IE浏览器.exe程序,输入url地址就可以成功录制了 . 但是由于公司网络配置环境改变了(猜测),现 ...
- SQLServer查询所有库表结构信息
1.查询数据库中的所有数据库名: SELECT Name FROM Master..SysDatabases ORDER BY Name 2.查询某个数据库中所有的表名: SELECT Name FR ...
- Scorpio-CSharp简介
Scorpio-CSharp是为了解决Unity游戏各个平台热更新的问题,纯c#实现 基于.net2.0 兼容所有c#平台 语法类似 javascript, 设计初衷是为了做一个所有人都能修改的热更新 ...
- Windows程序设再读笔记01-起步
1.从程序员角度看,统一的界面意味着编程人员可以使用windows自带的例程来构建许多的功能,例如菜单,对话框等.只用几行代码就可以实现很多复杂的功能.但是这同时也增加了一些限制,使得做出一个个性化的 ...
- java闭包
闭包就是在一个外部类A中声明了一个内部类B,然后这个内部类可以访问他自己B的作用域和外部类A的作用域.然后现在用另外一个类C创建了一个内部类B,那么这个内部类B可以访问C的作用域. 如果没有闭包,那B ...