目录
Runloop--概念
基本作用:
- 保持程序的持续运行
- 处理App中的各种事件(比如触摸事假、定时事件、selector事件)
- 节省CPU资源,提高程序性能:该做事时做事,改休息时休息。
iOS中有2套API来访问和使用Runloop:
- Foundation NSRunloop
- Core Foundation CFRunLoopRef
Runloop--获取Runloop对象
- Foundation
[NSRunloop currentRunLoop];//获取当前线程的Runloop对象
[NSRunloop mainRunLoop];//获取主线程的Runloop对象
- Core Foundation
CFRunloopGetCurrent();//获取当前线程的Runloop对象
CFRunLoopGetMain();//获取主线程的Runloop对象
- 互相转化方法
mainRunLoop.getCFRunLoop
Runloop--与线程的关系
每条线程都有唯一的一个与之对应的Runloop对象
主线程的Runloop已经自动创建好了,子线程的Runloop需要手动创建
Runloop在第一次获取时创建,在线程结束时销毁
Runloop--五大相关类
Core Foundation 中关于 Runloop的5个类
- CFRunLoopRef//本身
- CFRunLoopModeRef//运行模式
- CFRunLoopSourceRef//事件源输入源
- CFRunloopTimerRef//定时器
- CFRunLoopObserverRef//监听
CFRunLoopModeRef(运行模式)
CFRunLoopModeRef代表RunLoop的运行模式
- 一个Runloop包含若干个Mode,每个Mode又包含若干个Source/Timer/Observer
- 每次Runloop启动时,只能指定其中一个 Mode,这个Mode被称为CurrentMode
- 如果需要切换Mode,只能退出Loop,再重新指定一个Mode进入
- 这样做主要是为了分隔开不同组的Source/Timer/Observer,让其互不影响
系统默认注册了5个Mode:
- kCFRunLoopDefaultMode:App默认Mode,通常主线程是在这个Mode下运行
- UITrackingRunLoopMode:界面跟踪Mode,用于ScrollView追踪触摸滑动,保证界面滑动时不受其他Mode影响
- UIIntiallizationRunLoopMode:在刚启动App时进入的第一个Mode,启动完成后就不再使用
- GSEventReceiveRunLoopMode:接受系统事件的内部Mode,通常用不到
- kCFRunLoopCommonModes:这是一个占位用的Mode,不是一种真正的Mode
CFRunLoopSourceRef(输入源)
是事件源(输入源)
- Source0:非基于Port的(用户主动触发的事件,点击按钮,拖拽表格)
- Source1:基于Port的(系统内部的消息事件)
CFRunLoopTimerRef(定时器)
CFRunLoopTimerRef是基于时间的触发器
基本上说的就是NSTimer
CFRunLoopObserverRef(观察者)
是观察者,能够监听RunLoop的改变状态
//创建监听者
/*
1.怎么分配存储空间
2.要监听的状态 kCFRunLoopAllActivities所有的状态
3.是否持续监听
4.优先级,总是传0
5.当状态改变时候回调
*/
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
/*
kCFRunLoopEntry = (1UL << 0),即将进入runloop
kCFRunLoopBeforeTimers = (1UL << 1),即将处理timer事件
kCFRunLoopBeforeSources = (1UL << 2),即将处理source事件
kCFRunLoopBeforeWaiting = (1UL << 5),即将进入睡眠
kCFRunLoopAfterWaiting = (1UL << 6),被唤醒
kCFRunLoopExit = (1UL << 7),runloop退出
kCFRunLoopAllActivities = 0x0FFFFFFFU
*/
switch (activity) {
case kCFRunLoopEntry:
NSLog(@"即将进入runloop");
break;
case kCFRunLoopBeforeTimers:
NSLog(@"即将处理timer事件");
break;
case kCFRunLoopBeforeSources:
NSLog(@"即将处理source事件");
break;
case kCFRunLoopBeforeWaiting:
NSLog(@"即将进入睡眠");
break;
case kCFRunLoopAfterWaiting:
NSLog(@"被唤醒");
break;
case kCFRunLoopExit:
NSLog(@"runloop退出");
break;
default:
break;
}
});
/*
1.要监听哪个runloop
2.观察者
3.运行模式
NSDefaultRunLoopMode = kCFRunLoopDefaultMode
NSRunLoopCommonModes = kCFRunLoopCommonModes
*/
CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);
}
Runloop--应用
NSTimer
ImageView显示
PerformSelector
常驻线程
自动释放池
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
[runLoop run];
Runloop--面试题
1.什么是RunLoop?
从字面意思看是运行循环、跑圈
其实它内部就是do-while循环,在这个循环内部不断地处理各种任务(比如Source、Timer、Observer)一个线程对应一个RunLoop,主线程的RunLoop默认已经开启,子线程的RunLoop得手动启动(调用runloop方法)
RunLoop只能选择一个Mode启动,如果当前Mode中没有任何Source(Sources0、Sources1)、Timer,那么就直接退出RunLoop
2.自动释放池什么时候释放?
第一次创建:启动runloop
最后一次销毁:runloop退出的时候
其他时候创建和销毁:当runloop即将睡眠的时候销毁之前的释放池,重新创建一个新的
3.在开发中如何使用RunLoop?什么应用场景?
开启一个常驻线程(让一个子线程不进入消亡状态,等待其他线程发来消息,处理其他事件)
可以控制定时器在特定模式下执行
可以让某些事件(行为、任务)在特定模式下执行
可以添加Observer 监听RunLoop的状态,比如监听点击事件的处理(在所有点击事件之前做一些事情)
RunLoop--注意点
1.子线程runloop默认不创建
NSRunloop *loop= [NSRunloop currentRunLoop];//创建子线程runloop
[Loop run];//开启runloop
2.在runloop中有多个运行模式,但是runloop只能选择一种模式运行
3.mode里面至少有一个timer或者source