RunLoop概念
RunLoop 作用
- 保证程序的持续运行
- 处理App的各种事件(滑动, 定时器, selector)
- 节省CPU资源, 提高程序性能
- 默认启动的RunLoop是跟主线程相关联的, 主要处理与主线程相关的事件
RunLoop 循环图
RunLoop 对象
- Foundation: NSRunLoop (OC语言)
- Core Foundation: CFRunLoopRef (C语言)
RunLoop 与线程
- 每条线程都有唯一的一个与之对应的RunLoop对象
- 主线程的RunLoop随着程序已自动创建好, 但是子线程的RunLoop需要手动创建
- 获得主线程的RunLoop的方法是 [NSRunLoop mainRunLoop];
- 创建子线程的RunLoop的方法是[NSRumLoop currentRunLoop]; // apple不允许创建RunLoop
Runloop Mode
CFRunLoopModeRef 介绍
- CFRunLoopModeRef 代表了RunLoop的运行模式
- 一个RunLoop可以包含若干个Mode, 每个Mode包含若干个 Source/Timer/Observer
- 每次RunLoop启动时, 只能指定其中的一个Mode, 这个Mode被称作为currentMode
- 如果需要切换Mode, 需要退出RunLoop,再重新指定一个Mode进入,这样做的原因是为了分离不同的Source/Timer/Observer, 让其互不影响
CFRunLoopModeRef类型
- kCFRunLoopDefaultMode: App的默认Mode, 通常主线程是在该Mode下运行
- UITrackingRunLoopMode: 界面跟踪Mode, 用于ScrollView追踪触摸滑动, 保证界面滑动时, 不收其它Mode影响
- UIInitializationRunLoopMode: 在刚启动时App进入的第一个Mode, 启动完成后就不再使用
- GSEventReciveRunLoopMode: 接收系统事件的内部Mode, 一般不用
- kCFRunLoopCommonModes: 这是一个占位用的Mode, 不是真正的Mode
CFRunLoopTimerRef
// 自动加在RunLoop下 可以直接运行
// NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
// 添加
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
// NSRunLoopCommonModes = UITrackingRunLoopMode + NSDefaultRunLoopMode
CFRunLoopSourceRef
- Port-Based Sources 从其它线程或内核发出来的
- Custom Input Sources 自定义的
- CoCoa Perform Selector Sources
- Sources0: 非基于Port的
- Sources0:基于Port, 通过其他线程或者内核通信, 接受,分发系统时间
CFRunLoopObserverRef
/* Run Loop Observer Activities */
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
kCFRunLoopEntry = (1UL << 0), // 即将进入RunLoop
kCFRunLoopBeforeTimers = (1UL << 1), // 即将处理Timer
kCFRunLoopBeforeSources = (1UL << 2), // 即将处理 Sources
kCFRunLoopBeforeWaiting = (1UL << 5), // 即将进入休眠
kCFRunLoopAfterWaiting = (1UL << 6), // 即将从休眠中唤醒
kCFRunLoopExit = (1UL << 7), // 即将推出
kCFRunLoopAllActivities = 0x0FFFFFFFU // 活跃中
};
// 给runLoop添加观察者 需要CF类
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
NSLog(@"----%lu----", activity)
});
CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);
RunLoop内部逻辑