1. 概念api
runloop是运动循环,不断跑圈,无限循环框架
做用:
oop
保持程序的持续运行 (iOS程序一直活着的缘由)
性能
处理App中的各类事件(eg:触摸事件/定时器事件/selector事件【选择器·performSelector···】)spa
节省CPU资源,提升程序的性能(有事作事,没事休息)
线程
程序已启动,就开启了一个runloop无限循环,所以程序才能持续的运行code
#import <UIKit/UIKit.h>#import "AppDelegate.h"int main(int argc, char * argv[]) {@autoreleasepool {return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));}}
2. Runloop对象orm
1> 在iOS开发中有两套api来访问Runloopserver
Foundation框架【NSRunloop】(OC)对象
Core Foundation框架【CFRunloopRef】(C)
2> NSRunLoop和CFRunLoopRef都表明着RunLoop对象,它们是等价的,能够互相转换
3> NSRunLoop是基于CFRunLoopRef的一层OC包装,因此要了解RunLoop内部结构,须要多研究CFRunLoopRef层面的API(Core Foundation层面)
3. Runloop与线程的关系
1> Runloop和线程的关系:一个Runloop对应着一条惟一的线程
问题:如何让子线程不死
回答:给这条子线程开启一个Runloop
2> Runloop的建立:主线程Runloop已经建立好了,子线程的runloop须要手动建立
3> Runloop的生命周期:在第一次获取时建立,在线程结束时销毁
1. Foundation框架【NSRunloop】建立Runloop对象
// 获取当前线程下的Runloop, 懒加载的形式建立NSRunLoop * runloop1 = [NSRunLoop currentRunLoop];// 获取主线程下的RunloopNSRunLoop * runloop1 = [NSRunLoop mainRunLoop];
2. Core Foundation框架【CFRunloopRef】建立Runloop对象
// 获取当前线程下的Runloop, 懒加载的形式建立CFRunLoopRef runloop2 = CFRunLoopGetCurrent();// 获取主线程下的RunloopCFRunLoopRef runloop2 = CFRunLoopGetMain();
3. Runloop运行原理图
4. Runloop相关的类
CFRunloopRef
CFRunloopModeRef【Runloop的运行模式】
CFRunloopSourceRef【Runloop要处理的事件源】
CFRunloopTimerRef【Timer事件】
CFRunloopObserverRef【Runloop的观察者(监听者)】
Runloop要想跑起来,它的内部必需要有一个mode,mode中必须有source/observer/time,至少要有其中的一个
5. CFRunloopModeRef【Runloop的运行模式】
Runloop每次启动的时候只能指定一个运行模型,切换模式时必须退出当前的Runloop,再从新进入一个mode,是为了分割不一样组的定时器互不影响
kCFRunLoopDefaultMode:App的默认Mode,一般主线程是在这个Mode下运行
UITrackingRunLoopMode:界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其余 Mode 影响
UIInitializationRunLoopMode: 在刚启动 App 时第进入的第一个 Mode,启动完成后就再也不使用
GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,一般用不到
kCFRunLoopCommonModes: 这是一个占位用的Mode,不是一种真正的Mode
6. CFRunloopTimerRef【Timer事件】
1> NSTimer
- (void)timer0{NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(show) userInfo:nil repeats:YES];/* NSDefaultRunLoopMode -> kCFRunLoopDefaultMode 默认模式主线程中执行 NSRunLoopCommonModes -> kCFRunLoopDefaultMode/UITrackingRunLoopMode UITrackingRunLoopMode -> 界面追踪,其余不工做 */[[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];}
2. GCD定时器
GCD定时器必须必须保存起来才能使用
- (void)gcdTimer{NSLog(@"+++++++++");// 1.建立定时器dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));// 2.设置定时器/* 第一个参数:定时器 第二个参数:从哪一个时间开始 第三个参数:间隔时间 第四个参数:精确度, 0表明无偏差 */ dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 2.0 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);// 3.定时器触发事件 dispatch_source_set_event_handler(timer, ^{NSLog(@"----------");});// 4.开启定时器 dispatch_resume(timer);// GCD定时器建立是个局部变量须要保存才能执行 self.timer = timer;}
7. CFRunloopSourceRef【Runloop要处理的事件源】
(1)之前的分法
Port-Based Sources
Custom Input Sources
Cocoa Perform Selector Sources
(2)如今的分法
Source0:非基于Port的 (用户触发的时间)
Source1:基于Port的 (经过内核和其它线程相互发送消息)
8. CFRunloopObserverRef【Runloop的观察者(监听者)】
- (void)observer{// 建立一个观察者/* 第一个参数:获取内存的方式 第二个参数:监听哪些状态 第三个参数:是否持续监听 第四个参数:0 第五个参数:block代码块 kCFRunLoopEntry = (1UL << 0), 准备进入 kCFRunLoopBeforeTimers = (1UL << 1), 即将处理timer事件 kCFRunLoopBeforeSources = (1UL << 2), 即将处理source事件 kCFRunLoopBeforeWaiting = (1UL << 5), 即将进入休眠 kCFRunLoopAfterWaiting = (1UL << 6), 唤醒 kCFRunLoopExit = (1UL << 7), 退出 kCFRunLoopAllActivities = 0x0FFFFFFFU 全部 */CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {switch (activity) {case kCFRunLoopEntry:NSLog(@"准备进入");break;case kCFRunLoopBeforeTimers:NSLog(@"即将处理timer事件");break;case kCFRunLoopBeforeSources:NSLog(@"即将处理source事件");break;case kCFRunLoopBeforeWaiting:NSLog(@"即将进入休眠");break;case kCFRunLoopAfterWaiting:NSLog(@"唤醒");break;case kCFRunLoopExit:NSLog(@"退出");break;}});// 给runloop添加一个观察者CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(show) userInfo:nil repeats:YES];// 释放观察者CFRelease(observer);}
9. Runloop运行逻辑