1、Runloop 和 线程 的关系
1、runloop与线程是一一对应的,一个runloop对应一个核心的线程,为什么说是核心的,是因为runloop是可以嵌套的,但是核心的只能有一个,他们的关系保存在一个全局的字典里。
2、runloop是来管理线程的,当线程的runloop被开启后,线程会在执行完任务后进入休眠状态,有了任务就会被唤醒去执行任务。
3、runloop在第一次获取时被创建,在线程结束时被销毁。
4、对于主线程来说,runloop在程序一启动就默认创建好了。
5、对于子线程来说,runloop是懒加载的,只有当我们使用的时候才会创建,所以在子线程用定时器要注意:确保子线程的runloop被创建,不然定时器不会回调。
2、Runloop 介绍
CFRunLoopRef:代表RunLoop的对象
CFRunLoopModeRef:RunLoop的运行模式
CFRunLoopSourceRef:就是RunLoop模型图中提到的输入源/事件源
CFRunLoopTimerRef:就是RunLoop模型图中提到的定时源
CFRunLoopObserverRef:观察者,能够监听RunLoop的状态改变
2.1 运行模式
每次RunLoop启动时,只能指定其中一个运行模式(CFRunLoopModeRef),这个运行模式(CFRunLoopModeRef)被称作CurrentMode。
如果需要切换运行模式(CFRunLoopModeRef),只能退出Loop,再重新指定一个运行模式(CFRunLoopModeRef)进入。
这样做主要是为了分隔开不同组的输入源(CFRunLoopSourceRef)、定时源(CFRunLoopTimerRef)、观察者(CFRunLoopObserverRef),让其互不影响。
NSDefaultRunLoopMode:App的默认Mode,通常主线程是在这个Mode下运行
UITrackingRunLoopMode:界面跟踪Mode,用于ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响
UIInitializationRunLoopMode:在刚启动App时第进入的第一个 Mode,启动完成后就不再使用
GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,通常用不到
NSRunLoopCommonModes:这是一个占位用的Mode,不是一种真正的Mode
2.1.1 NSTimer使用
1、加入到NSDefaultRunLoopMode 模式下
// 定义一个定时器,约定两秒之后调用self的run方法
NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
// 将定时器添加到当前RunLoop的NSDefaultRunLoopMode下
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
等同于下面的写法
// 等效于上面的写法 这句代码调用了scheduledTimer返回的定时器,NSTimer会自动被加入到了RunLoop的NSDefaultRunLoopMode模式下。 [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
当页面中存在scrollView 滑动的时候,runloop的模式会切换到 UITrackingRunLoopMode,此时定时器任务停止。
2、加入 UITrackingRunLoopMode 模式下(测试用,实际中不这么玩)
NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];
当页面中scrollView 滑动的时候,定时任务才启动运行
3、加入到NSRunLoopCommonModes 模式下
NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
将NSTimer添加到当前RunLoop的NSRunLoopCommonModes下,我们就可以让NSTimer在不做操作和拖动scrollView 两种情况下 正常运行。
3、 RunLoop 运行原理
1、通知观察者RunLoop已经启动
2、通知观察者即将要开始的定时器
3、通知观察者任何即将启动的非基于端口的源
4、启动任何准备好的非基于端口的源
5、如果基于端口的源准备好并处于等待状态,立即启动;并进入步骤9
6、通知观察者线程进入休眠状态
7、将线程置于休眠知道任一下面的事件发生: 1、 某一事件到达基于端口的源 定时器启动 2、 RunLoop设置的时间已经超时 3、 RunLoop被显示唤醒
8、通知观察者线程将被唤醒
9、处理未处理的事件 :1、如果用户定义的定时器启动,处理定时器事件并重启RunLoop。进入步骤2 2、如果输入源启动,传递相应的消息 3、如果RunLoop被显示唤醒而且时间还没超时,重启RunLoop。进入步骤2
10、通知观察者RunLoop结束。
网友评论