NSRunLoop
是IOS消息机制的处理模式主要作用
mainRunLoop/CFRunLoopGetMain
currentRunLoop/CFRunLoopGetCurrent
运行模式
(CFRunLoopModeRef)
默认模式
NSDefaultRunLoopMode
:App的默认Mode,通常主线程是在这个Mode下运行UITrackingRunLoopMode
:界面跟踪Mode,用于ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响UIInitializationRunLoopMode
:在刚启动App时第进入的第一个 Mode,启动完成后就不再使用GSEventReceiveRunLoopMode
: 接受系统事件的内部 Mode,通常用不到NSRunLoopCommonModes
:这是一个占位用的Mode,不是一种真正的Mode结构图
// 新建NSTimer对象
NSTimer *timer = [NSTimer timerWithTimeInterval:5.0 target:self selector:@selector(show) userInfo:nil repeats:YES];
// 将NSTimer添加到RunLoop中,并且告诉系统,当前Tiemr只有在RunLoop的默认模式下才有效
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
// 所以在UITrackingRunLoopMode模式下,定时器的方法不会执行,但定时器仍计时
[[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];
将NSTimer添加到RunLoop中,并且告诉系统,在所有被"标记"common的模式都可以运行,UITrackingRunLoopMode和kCFRunLoopDefaultMode都被标记为了common模式,所以只需要将timer的模式设置为forMode:NSRunLoopCommonModes,就可以在默认模式和追踪模式都能够运行
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
如果是通过scheduledTimerWithTimeInterval创建的NSTimer, 默认就会添加到RunLoop得DefaultMode中 , 所以它会自动运行
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(show) userInfo:nil repeats:YES];
// 虽然默认已经添加到DefaultMode中,但是我们也可以自己修改它的模式
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
// 1.创建一个定时器
// 获取一个全局并发队列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
// 第四个参数:传递一个队列,该队列对应了将来的回调方法在哪个线程中执行
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
// 2.指定定时器开始的时间和间隔的时间, 以及精准度
// 开始时间
dispatch_time_t startTime = dispatch_time(DISPATCH_TIME_NOW, 3.0 * NSEC_PER_SEC);
// 间隔时间
uint64_t interval = 1.0 * NSEC_PER_SEC;
// 设置定时器
/*
第1个参数: 需要给哪个定时器设置
第2个参数: 定时器开始的时间/DISPATCH_TIME_NOW立即执行
第3个参数: 定时器开始之后的间隔时间
第4个参数: 定时器间隔执行的精准度, 传入0代表最精准(尽量的让定时器精准), 传入一个大于0的值, 代表多少秒的范围是可以接受的
第四个参数存在的意义: 主要是为了提高程序的性能
注意点: Dispatch的定时器接收的时间是纳秒
*/
dispatch_source_set_timer(timer, startTime, interval, 0 * NSEC_PER_SEC);
// 3.指定定时器的回调方法
/*
第1个参数: 需要给哪个定时器设置
第2个参数: 需要回调的block
*/
dispatch_source_set_event_handler(timer, ^{
NSLog(@"++++++++++++++ %@", [NSThread currentThread]);
});
// 4.开启定时器
dispatch_resume(timer);
CFRunLoopObserverRef
*******viewDidLoad********
// 创建Observer
/*
第1个参数: 指定如何给observer分配存储空间
第2个参数: 需要监听的状态类型/ kCFRunLoopAllActivities监听所有状态
第3个参数: 是否每次都需要监听
第4个参数: 优先级
第5个参数: 监听到状态改变之后的回调
*/
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
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(@"即将退出");
break;
default:
break;
}
});
// 给主线程的RunLoop添加一个观察者
/*
第1个参数: 需要给哪个RunLoop添加观察者
第2个参数: 需要添加的Observer对象
第3个参数: 在哪种模式下可以可以监听
*/
CFRunLoopAddObserver(CFRunLoopGetMain(), observer, kCFRunLoopDefaultMode);
// 释放对象
CFRelease(observer);
[NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:@selector(show) userInfo:nil repeats:YES];
********show********
- (void)show{
NSLog(@"%s",__func__);
}
![Observer状态变化 . . .]
逻辑
observer
timer
source
(void)viewDidLoad
{
XMGThread *thread = [[XMGThread alloc] initWithTarget:self selector:@selector(show) object:nil];
self.thread = thread;
[thread start];
}
(void)touchesBegan:(NSSet )touches withEvent:(UIEvent )event
{
// 默认情况下一个线程只能使用一次, 也就是说只能执行一个操作, 执行完毕之后就不能使用了
[self performSelector:@selector(test) onThread:self.thread withObject:nil waitUntilDone:YES];
}
// test方法不会执行
```
子线程RunLoop常驻
// 1.子线程的NSRunLoop需要手动创建
// 2.子线程的NSRunLoop需要手动开启
// 3.如果子线程的NSRunLoop没有设置source or timer, 那么子线程的NSRunLoop会立刻关闭
// 无含义,设置子线程为常住线程,让子线程不关闭
// [[NSRunLoop currentRunLoop] addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
NSTimer *timer = [NSTimer timerWithTimeInterval:5.0 target:self selector:@selector(test) userInfo:nil repeats:YES];
// 会添加到当前子线程
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
[[NSRunLoop currentRunLoop] run];