iOS中的RunLoop
来源:互联网 发布:linux date 北京时间 编辑:程序博客网 时间:2024/06/04 00:55
iOS中的RunLoop
什么是RunLoop
从字面上理解就是一个运行循环,我们一般程序就是执行一个线程,是一条直线.有起点终点.而runloop就是一直在线程上面画圆圈,一直在跑圈,在不断跑圈中,一直在检测一些点击事件、定时器等等,一旦检测到就开始执行,执行结束后再睡眠,睡眠中再检测,除非切断否则一直在运行,否则就一直在循环。其内部的结构是一个do-while循环,在这个循环内部不断处理各种任务(比如timer、source、Observer)
RunLoop基本作用
- 保持程序的持续运行,App持续运行就是因为有RunLoop
- 处理App中的各种事件(比如触摸事件、定时事件、Selector事件)
- 节省CPU资源,提高程序性能,该做事时做事,该休息时休息
RunLoop对象
- Foundation
NSRunLoop Core Foundation
CFRunLoopRefNSRunLoop和CFRunLoopRef都代表着RunLoop对象,NSRunLoop是基于CFRunLoopRef的一层OC的包装
RunLoop与线程
- 每条线程都有唯一的一个与之相对应的RunLoop对象
- 主线程的RunLoop系统已经创建好了,子线程的RunLoop需要主动创建
RunLoop在第一次获取时创建,在线程结束时销毁
// 全局的Dictionary,key 是 pthread_t, value 是 CFRunLoopRef static CFMutableDictionaryRef loopsDic; // 访问 loopsDic 时的锁 static CFSpinLock_t loopsLock;// 获取一个 pthread 对应的 RunLoop。CFRunLoopRef _CFRunLoopGet(pthread_t thread) { OSSpinLockLock(&loopsLock); if (!loopsDic) { // 第一次进入时,初始化全局Dic,并先为主线程创建一个 RunLoop。 loopsDic = CFDictionaryCreateMutable(); CFRunLoopRef mainLoop = _CFRunLoopCreate(); CFDictionarySetValue(loopsDic, pthread_main_thread_np(), mainLoop); } // 直接从 Dictionary 里获取。 CFRunLoopRef loop = CFDictionaryGetValue(loopsDic, thread)); if (!loop) { // 取不到时,创建一个 loop = _CFRunLoopCreate(); CFDictionarySetValue(loopsDic, thread, loop); // 注册一个回调,当线程销毁时,顺便也销毁其对应的 RunLoop。 _CFSetTSD(..., thread, loop, __CFFinalizeRunLoop); } OSSpinLockUnLock(&loopsLock); return loop;}CFRunLoopRef CFRunLoopGetMain() { return _CFRunLoopGet(pthread_main_thread_np());}CFRunLoopRef CFRunLoopGetCurrent() { return _CFRunLoopGet(pthread_self());}
从上面的代码可以看出,线程和 RunLoop 之间是一一对应的,其关系是保存在一个全局的 Dictionary 里。线程刚创建时并没有 RunLoop,如果你不主动获取,那它一直都不会有。RunLoop 的创建是发生在第一次获取时,RunLoop 的销毁是发生在线程结束时。你只能在一个线程的内部获取其 RunLoop(主线程除外)。
//获取当前线程的RunLoop[NSRunLoop currentRunLoop]; //获取主线程的RunLoop[NSRunLoop mainRunLoop];//获取当前线程的RunLoopCFRunLoopGetMain();//获取主线程的RunLoopCFRunLoopGetCurrent();
注:NSRunLoop初始化不需要alloc,只需要在该线程里调用[NSRunLoop currentRunLoop],
RunLoop与相关类
(主要针对Core Foundation中的RunLoop的5个类)
- CFRunLoopRef
- CFRunLoopModeRef
- CFRunLoopSourceRef
- CFRunLoopTimerRef
CFRunLoopObserverRef
其中 CFRunLoopModeRef 类并没有对外暴露,只是通过 CFRunLoopRef 的接口进行了封装。他们的关系如下:
CFRunLoopModeRef
- CFRunLoopModeRef代表RunLoop得运行模式
- 一个RunLoop包含了若干个Mode,每个Mode又包含了若干个Source/Timer/Observer
- 每次RunLoop启动时,只能指定其中一个Mode,这个Mode被称作CurrentMode
- 如果需要切换Mode,只能退出Loop,再重新指定一个Mode进入循环
每个Mode苦于设置自己的 Source/Timer/Observer,让其互不影响
系统默认注册了5个Mode(苹果只开放了前俩个)
- kCFRunLoopDefaultMode:App的默认Mode,通常主线程是这个Mode下运行
- UITrackingRunLoopMode:界面跟踪Mode,用于ScrollerView追踪触摸滑动,保证界面滑动时不受其他Mode影响
- UIInitalizaationRunLoopMode:在刚启动App时进入的第一个Mode,启动完成后就不再使用
- GSEventReceiveRunLoopMode:接受系统事件内部的Mode,通常用不到
- kCFRunLoopCommonModes:这是占位的Mode,不是真正的Mode
CFRunLoopTimerRef
- CFRunLoopTimerRef是一个基于时间触发器
CFRunLoopSourceRef
- CFRunLoopSourceRef是事件源(输入源)
- 按照官方文档,Source的理论分类
- Port-Based Source
- Custom Input Source
- Cocoa Perform Selector Sources
- 按照函数调用栈,Source的实践分类
- Source0:非基于Prot的
- Source1:基于Prot的,通过内核和其他线程通信,接受、分发系统事件
CFRunLoopObserverRef
- CFRunLoopObserverRef是观察者,能够监听RunLoop的状态改变
可以监听的时间点有以下几个
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) { kCFRunLoopEntry = (1UL << 0),//即将进入Runloop kCFRunLoopBeforeTimers = (1UL << 1),//即将处理Timer kCFRunLoopBeforeSources = (1UL << 2),//即将处理Source事件 kCFRunLoopBeforeWaiting = (1UL << 5),//即将进入休眠 kCFRunLoopAfterWaiting = (1UL << 6),//从刚才休眠中唤醒 kCFRunLoopExit = (1UL << 7),//即将退出runloop kCFRunLoopAllActivities = 0x0FFFFFFFU//监听所有状态};
* CF的内存管理*
- 1、凡是带有Create、copy、retain等字眼的函数,创建出来的对象,都需要在最后做一次release
- 2、release函数:CFRelease(observer);
RunLoop处理逻辑
RunLoop在开发中的使用场景
1、开启一个常驻线程(让一个子线程不进入消亡状态,等待其他线程发来消息,处理事件)
- 在子线程中开启一个定时器
- 在子线程中进行长期监控一个行为事件
2、可以控制定时器在特定模式下执行
3、可以让某些事件在特定模式下执行
4、可以添加Observer监听RunLoop的状态,比如监听点击事件的处理(在所有点击事件之前做一些事情)
最后,附上以上的demo,git:(https://github.com/hejiasu/RunLoop)
- iOS中的RunLoop
- iOS中的Runloop
- ios开发中的runloop
- iOS中的RunLoop
- iOS中的RunLoop
- 浅谈iOS中的RunLoop
- iOS中的runtime和runloop
- iOS中的RunLoop 和 android 中的Looper
- iOS runloop
- iOS runloop
- iOS RunLoop
- iOS runloop
- <iOS>RunLoop
- iOS RUNLOOP
- iOS Runloop
- iOS - RunLoop
- iOS runloop
- iOS--Runloop
- 深入理解拉格朗日乘子法(Lagrange Multiplier) 和KKT条件
- Controlled-Channel Attacks: Deterministic Side Channels for Untrusted Operating Systems
- PHP实现http与https转化
- springmvc返回路径错误的问题
- ESB和SOAP的概念
- iOS中的RunLoop
- android ffmpeg neno优化
- 黑匣子
- Dubbo+Zookeeper+Spring整合应用篇-Dubbo基于Zookeeper实现分布式服务
- Autofuc None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructor
- OC--NSMutableString可变字符串
- JS表单验证-12个常用的JS表单验证
- 【九度OJ】题目1169:比较奇偶数个数 解题报告
- SQL server安装过程