1.概述
什么是Runloop
如果没有Runloop
- CFRunloopRef开源地址: opensource.apple.com/tarballs/CF…
Runloop与线程
- 每条线程都有唯一与之对应的Runloop对象
- Runloop保存在一个全局的Dictionary里,线程作为key,Runloop作为value.
- 线程刚创建时并没有Runloop对象,Runloop会在第一次获取它时创建
- Runloop会在线程结束时销毁
- 主线程的Runloop已经自动获取(创建),子线程默认没有开启Runloop。
// NSRunLoop *runloop;
// CFRunLoopRef runloop2;
// runloops[thread] = runloop; //保存在全局字典里,线程为key
// NSRunLoop *runloop = [NSRunLoop currentRunLoop];
// CFRunLoopRef runloop2 = CFRunLoopGetCurrent();
// NSArray *array;
// CFArrayRef arry2;
//
// NSString *string;
// CFStringRef string2;
NSLog(@"%p %p", [NSRunLoop currentRunLoop], [NSRunLoop mainRunLoop]);
NSLog(@"%p %p", CFRunLoopGetCurrent(), CFRunLoopGetMain());
CFRunLoopGetCurrent()和[NSRunLoop currentRunLoop]地址不一样。
Runloop模式
- CFRunLoopModeRef代表Runloop的运行模式
- 一个Runloop包含若干个Mode,每个Mode又包含若干个Source0/Source1/Timer/Observer
- Runloop启动时只能选择其中一个Mode,作为currentMode
- 如果需要切换Mode,只能退出当前Loop,再重新选择一个Mode进入
- 不同组的Source0/Source1/Timer/Observer能分割开来,互不影响
- 如果Mode里没有任何Source0/Source1/Timer/Observer,Runloop会立马退出
常见的2种Mode
-
KCFRunloopDefaultModel(NSDefaultRunloopMode):App的默认Mode,通常主线程是在这个Mode下运行
-
UITrackingRunloopMode : 界面跟踪Mode,用于ScrollView跟踪触摸滑动,保证界面滑动时不受其他Mode影响。
-
切换模式并不会导致Runloop退出。
Runloop运行模式
-
可以看出触摸事件是通过Source0处理,然后调用
__handleEventQueueInternal,再调用__handleEventQueueInternal -
系统事件是由Source1捕捉,然后交给Source0处理。
-
Observers
- UI刷新,线程睡觉前刷新UI.线程没什么事干就睡觉,
self.view.backColor = [uicolor redcolor];不是一执行这个代码就生效,会先记住这个事件。通过observe监听线程状态,监听到要睡觉前刷新UI。 - Autorelease pool 线程睡觉前,清理需要释放的对象。
- BeforeWaiting 休眠前
- AfterWaiting 唤醒
- UI刷新,线程睡觉前刷新UI.线程没什么事干就睡觉,
-
程序所有代码,都是由Runloop决定什么时候去执行。
void observeRunLoopActicities(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info)
{
switch (activity) {
case kCFRunLoopEntry:
NSLog(@"kCFRunLoopEntry");
break;
case kCFRunLoopBeforeTimers:
NSLog(@"kCFRunLoopBeforeTimers");
break;
case kCFRunLoopBeforeSources:
NSLog(@"kCFRunLoopBeforeSources");
break;
case kCFRunLoopBeforeWaiting:
NSLog(@"kCFRunLoopBeforeWaiting");
break;
case kCFRunLoopAfterWaiting:
NSLog(@"kCFRunLoopAfterWaiting");
break;
case kCFRunLoopExit:
NSLog(@"kCFRunLoopExit");
break;
default:
break;
}
}
// 创建Observer
// 第二个参数:监听哪种activity,这里是监听全部
// 第三个参数:是否重复监听
// 第四个参数: 监听顺序。这里不按照顺序监听
// 第五个参数需传进一个C语言方法
// 第六个参数则是第五个参数方法的info参数
CFRunLoopObserverRef observer = CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, observeRunLoopActicities, NULL);
// 添加Observer到RunLoop中
//kCFRunLoopCommonModes默认包括kCFRunLoopDefaultMode、UITrackingRunLoopMode
CFRunLoopAddObserver(CFRunLoopGetMain(), observer, kCFRunLoopCommonModes);
// 释放
CFRelease(observer);
// 另一种方法创建observer
// 创建Observer
// CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
// switch (activity) {
// case kCFRunLoopEntry: {
// CFRunLoopMode mode = CFRunLoopCopyCurrentMode(CFRunLoopGetCurrent());
// NSLog(@"kCFRunLoopEntry - %@", mode);
// CFRelease(mode);
// break;
// }
//
// case kCFRunLoopExit: {
// CFRunLoopMode mode = CFRunLoopCopyCurrentMode(CFRunLoopGetCurrent());
// NSLog(@"kCFRunLoopExit - %@", mode);
// CFRelease(mode);
// break;
// }
//
// default:
// break;
// }
// });
// // 添加Observer到RunLoop中
// CFRunLoopAddObserver(CFRunLoopGetMain(), observer, kCFRunLoopCommonModes);
// // 释放
// CFRelease(observer);
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
//观察source
// NSLog(@"%s",__func__);
// 观察NSTimer
[NSTimer scheduledTimerWithTimeInterval:3.0 repeats:NO block:^(NSTimer * _Nonnull timer) {
NSLog(@"定时器-----------");
}];
}
观察滚动页面,ViewController里加一个UITextView,用下面代码监听:
// 另一种方法创建observer
// 创建Observer
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
switch (activity) {
case kCFRunLoopEntry: {
CFRunLoopMode mode = CFRunLoopCopyCurrentMode(CFRunLoopGetCurrent());
NSLog(@"kCFRunLoopEntry - %@", mode);
CFRelease(mode); //copy出来的需要释放
break;
}
case kCFRunLoopExit: {
CFRunLoopMode mode = CFRunLoopCopyCurrentMode(CFRunLoopGetCurrent());
NSLog(@"kCFRunLoopExit - %@", mode);
CFRelease(mode);
break;
}
default:
break;
}
});
// 添加Observer到RunLoop中
CFRunLoopAddObserver(CFRunLoopGetMain(), observer, kCFRunLoopCommonModes);
// 释放
CFRelease(observer);