RunLoop最细详解

2022-08-30  本文已影响0人  奋拓达

Runloop的实现机制

RunLoop 通过mach_msg()函数接收、发送消息。它的本质是调用函数 mach_msg_trap(),相当于是一 个系统调用,会触发内核状态切换。在用户态调用时会切换到内核态; 而内核态中内核实现了mach_msg()函数会完成实际的工作。

RunLoop基本作用

RunLoop详解

Mode详解

Mode内部Source0/ Source1/ Timer/ Observer解析

RunLoop运行逻辑

内部不断的循环处理block,source,Timer等,处理完成就休眠,被消息唤醒就继续处理。

Runloop 数据结构

RunLoop与线程的关系

NSTimer与RunLoop的关系

CADisplayLink 是一个和屏幕刷新率一致的定时器,在快速滑动 TableView 时,即使一帧的卡顿也会 让用户有所察觉。 FaceBook开源的 AsyncDisplayLink 就是为了解决界面卡顿的问题,其内部也用 到了 RunLoop。

NSTimer其实就是 CFRunLoopTimerRef(基于时间的触发器) ,他们之间是tool-free bridged 的。一个 NSTimer 注册到RunLoop后, RunLoop会为其重复的时间点注册好事件。例如 10:00, 10:10, 10:20 这几个时间点。 RunLoop为了节省资源,并不会在非常准确的时间点回调这个 Timer。Timer 有个属性叫做Tolerance(宽容度),标示了当时间点到后,容许有多少最大误差。
如果某个时间点被错过了,例如执行了一个很长的任务,则那个时间点的回调也会跳过去,不会延后执行。就比如等公交,如果 10:10 时我忙着玩手机错过了那个点的公交,那我只能等 10:20 这一趟了。

__block NSInteger count = 0;
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
        NSLog(@"%ld",(long)++count);
}];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

RunLoop应用场景

RunLoop对象及创建

1.获取当前的RunLoop

NSRunLoop *runloop = [NSRunLoop currentRunLoop]; 
CFRunLoopRef runloop = CFRunLoopGetCurrent();

2.主线程RunLoop对象

NSRunLoop *runloop = [NSRunLoop mainRunLoop];
CFRunLoopRef runloop = CFRunLoopGetMain();

怎么创建一个常驻线程?

NSRunLoop *runloop = [NSRunLoop currentRunLoop];
[[NSRunLoop currentRunLoop] addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
[runloop run];

怎样保证子线程数据回来更新 UI 的时候不打断用户的滑动操作?

当子线程请求数据的同时滑动当前页面,如果数据请求成功要切回主线程更新 UI,那么就会影响当 前正在滑动的体验。此时我们将更新UI放到主线程中执行即可,等滑动停止由子线程切换到主线程更新UI。

[self performSelectorOnMainThread: @selector(readLoad) withObject:nil waitUntilDone:NO modes:@[NSDefaultRunLoopMode]];

观察者observer怎么监听Runloop状态

typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
    // 即将进入runloop
    kCFRunLoopEntry = (1UL << 0),
    // 即将处理timer
    kCFRunLoopBeforeTimers = (1UL << 1),
    // 即将处理source
    kCFRunLoopBeforeSources = (1UL << 2),
    // 即将进入休眠
    kCFRunLoopBeforeWaiting = (1UL << 5),
    // 休眠后唤醒
    kCFRunLoopAfterWaiting = (1UL << 6),
    // 退出runloop
    kCFRunLoopExit = (1UL << 7),
    // runloop所有活动
    kCFRunLoopAllActivities = 0x0FFFFFFFU
};

扩展知识

上一篇下一篇

猜你喜欢

热点阅读