RunLoop
2018-04-14 本文已影响16人
前年的邂逅_Jerry
一、RunLoop是事件接受与分发机制的一个实现。
二、RunLoop中的五种模式:
1. kCFRunLoopDefaultMode:App的默认Mode,通常主线程是在这个Mode下运行
2. UITrackingRunLoopMode:界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响
3. UIInitializationRunLoopMode: 在刚启动 App 时第进入的第一个 Mode,启动完成后就不再使用
4. GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,通常用不到
5. kCFRunLoopCommonModes: 这是一个占位用的Mode,作为标记kCFRunLoopDefaultMode和UITrackingRunLoopMode用,并不是一种真正的Mode
三、每个RunLoop中有多个Model Item,每个Model item包含如下:<Set>Source、<Array>Time、<Array>Observe。
四、Source种类
1、基于Port
2、自定义的
链接:https://www.cnblogs.com/ioshe/p/5489112.html
五、Time。
定时器
六、Observe
-(void)observerCreate{
//1.创建监听者
/*
第一个参数:怎么分配存储空间
第二个参数:要监听的状态 。kCFRunLoopAllActivities 所有的状态
第三个参数:是否持续监听
第四个参数:优先级 总是传0
第五个参数:当状态改变时候的回调
*/
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(@"runloop退出");
break;
default:
break;
}
});
//2.添加监听者
/*
第一个参数:要监听哪个runloop
第二个参数:观察者
第三个参数:运行模式
*/
CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);
}
7、应用场景:
1、在runloop中添加定时器。定时器在不同模式上切换。
2、延迟执行performSelecter: withObject: afterDelay
相关方法是怎样被执行的?在子线程中也是一样的吗?
在子线程中添加performSelecter: withObject: afterDelay
实际上是将定时器添加到runLoop中,需要[[NSRunLoop currentRunLoop] run];
才能执行performSelect
方法,执行完后会自动将时间源移除,不用考虑僵尸线程的问题。僵尸线程讲解链接:https://www.jianshu.com/p/a20c4bdf3415。
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self performSelector:@selector(performSelect) withObject:nil afterDelay:3];
NSRunLoop * runLoop = [NSRunLoop currentRunLoop];
NSLog(@"runloop = %@",runLoop);
[[NSRunLoop currentRunLoop] run];
});
- (void)performSelect{
NSLog(@"%s",__func__);
}
runLoop打印结果:
runloop = <CFRunLoop 0x7ffe1c609fe0 [0x1063b17b0]>{wakeup port = 0x5807, stopped = false, ignoreWakeUps = true,
current mode = (none),
common modes = <CFBasicHash 0x7ffe1c60ad40 [0x1063b17b0]>{type = mutable set, count = 1,
entries =>
2 : <CFString 0x1063d1b40 [0x1063b17b0]>{contents = "kCFRunLoopDefaultMode"}
}
,
common mode items = (null),
modes = <CFBasicHash 0x7ffe1c60a0a0 [0x1063b17b0]>{type = mutable set, count = 1,
entries =>
2 : <CFRunLoopMode 0x7ffe1c609420 [0x1063b17b0]>{name = kCFRunLoopDefaultMode, port set = 0x5707, timer port = 0x590b,
sources0 = (null),
sources1 = (null),
observers = (null),
timers = <CFArray 0x7ffe1c609f50 [0x1063b17b0]>{type = mutable-small, count = 1, values = (
0 : <CFRunLoopTimer 0x7ffe1c60e5c0 [0x1063b17b0]>{valid = Yes, firing = No, interval = 0, tolerance = 0, next fire date = 545451740 (2.99986506 @ 32529849429331), callout = (Delayed Perform) ViewController performSelect (0x1057f7f97 / 0x105667c70) (/Users/Jerry/Library/Developer/CoreSimulator/Devices/D7925E35-7007-42DD-929E-C26FA54C8468/data/Containers/Bundle/Application/CDCE0849-7D22-4C4E-BE8F-12A4EAB35075/Demo1.app/Demo1), context = <CFRunLoopTimer context 0x7ffe1c60ccf0>}
)},
currently 545451737 (32526849538688) / soft deadline in: 2.99989061 sec (@ 32529849429331) / hard deadline in: 2.99989035 sec (@ 32529849429331)
},
}
}
另一种使用方法:
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 2.2*NSEC_PER_SEC);
dispatch_after(time, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSRunLoop * runLoop = [NSRunLoop currentRunLoop];
NSLog(@"runloop = %@",runLoop);
[self performSelect];
});
3、NSPort来产生常驻线程。
参考链接:http://www.imlifengfeng.com/blog/?p=487
4、AF2.6.3之前,请求网络时,将请求数据的子线程放在DefaultModel和TrackingModel下。
参考链接https://blog.csdn.net/u011619283/article/details/53433243