美文网首页
Runloop - 工作流程

Runloop - 工作流程

作者: xxttw | 来源:发表于2023-06-11 23:14 被阅读0次
  • 运行循环, 程序一直在循环的做一些事情
    处理程序的各种事件, 比如用户触摸事件, 定时器事件等
    节省CPU资源, 提高程序性能, 有任务的时候执行任务, 没有任务的时候进入休眠
  • NSRunloop CFRunloopRef
runloop与线程
  • runloop和线程是1对1的关系
    子线程刚创建的时候没有runloop对象, 在第一次获取它的时候创建
    主线程runloop已经自动创建, 子线程默认没有开启runloop
    runloop会在线程结束时销毁
runloop调用流程
image.png
    // 通知observer 进入Loop
    __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry);
    // 即将处理timer
    __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeTimers);
    // 即将处理sources
    __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeSources);
   // 处理Source0
    sourceHandledThisLoop = __CFRunLoopDoSources0(rl, rlm, stopAfterHandle);
 // 处理Source1
  __CFRunLoopDoSource1(rl, rlm, rls, msg, msg->msgh_size, &reply)) 

    // 即将休眠
    __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeWaiting);
    __CFRunLoopSetSleeping(rl);

   // 从休眠中唤醒
    __CFRunLoopUnsetSleeping(rl);
    __CFRunLoopDoObservers(rl, rlm, kCFRunLoopAfterWaiting);
    // 通知observer 退出Loop
    __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit);
  1. 通知Observers : 进入Loop
  2. 通知Observers: 即将处理Timer
  3. 通知Observers: 将处理Source
  4. 如果有Source0,处理Source0
  5. 如果有Source1,处理Source1 这里的意思是指被source1唤醒, source包含timer ,gcd,source1
  6. 通知Observers: 即将进入休眠
  7. 通知Observers: 从休眠中唤醒
  8. 通过Observers: 退出Loop


    image.png
{
    /// 1. 通知Observers,即将进入RunLoop
    /// 此处有Observer会创建AutoreleasePool: _objc_autoreleasePoolPush();
    __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(kCFRunLoopEntry);
    do {
 
        /// 2. 通知 Observers: 即将触发 Timer 回调。
        __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(kCFRunLoopBeforeTimers);
        /// 3. 通知 Observers: 即将触发 Source (非基于port的,Source0) 回调。
        __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(kCFRunLoopBeforeSources);
        __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__(block);
 
        /// 4. 触发 Source0 (非基于port的) 回调。
        __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__(source0);
        __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__(block);
 
        /// 6. 通知Observers,即将进入休眠
        /// 此处有Observer释放并新建AutoreleasePool: _objc_autoreleasePoolPop(); _objc_autoreleasePoolPush();
        __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(kCFRunLoopBeforeWaiting);
 
        /// 7. sleep to wait msg.
        mach_msg() -> mach_msg_trap();
        
 
        /// 8. 通知Observers,线程被唤醒
        __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(kCFRunLoopAfterWaiting);
 
        /// 9. 如果是被Timer唤醒的,回调Timer
        __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__(timer);
 
        /// 9. 如果是被dispatch唤醒的,执行所有调用 dispatch_async 等方法放入main queue 的 block
        __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(dispatched_block);
 
        /// 9. 如果如果Runloop是被 Source1 (基于port的) 的事件唤醒了,处理这个事件
        __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__(source1);
 
 
    } while (...);
 
    /// 10. 通知Observers,即将退出RunLoop
    /// 此处有Observer释放AutoreleasePool: _objc_autoreleasePoolPop();
    __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(kCFRunLoopExit);
}
runloop休眠的实现原理

通过mach_msg()内核api 从用户态切换到内核态, 没有消息就让线程休眠, 有消息就唤醒线程, 又回到用户态处理想处理的事情

source0
  • 点击事件
  • 触摸事件
source1
  • 基于Port的线程间通信
  • 系统事件捕捉
observers
  • 监听runloop各种状态切换
  • UI刷新事件(beforeWaiting)
  • AutoreleasePool释放对象(beforeWaiting)
timers

定时器
performSelector:withObject:afterDelay;

image.png
CFRunloopModeRef

runloop的运行模式 当前运行的mode, 称之为currentMode
一个runloop会包含1个或多个mode, 每个mode都会有若干个source0/source1/observer/timer
如果要切换mode, 需要退出当前loop循环, 再重新选择一个mode进入
不同mode中的 source0,1/observer/timer互相独立, 互不影响
如果mode里没有任何任务source0,1/observer/timer, runloop会立刻退出
常见的两种Mode
kCFRunLoopDefaultMode(NSDefaultRunLoopMode) : 为程序的默认Mode, 通常主线程在这个Mode下运行
UITrackingRunLoopMode : 界面跟踪Mode, 通常用于列表滑动, 保证界面滑动时不受其他Mode影响

CFRunLoopObserverRef
image.png
__CFRunLoop
struct __CFRunLoop {
    pthread_t _pthread;                              // 线程
    CFMutableSetRef _commonModes;    所有被标记为common的模式会添加到这个modes下
    CFMutableSetRef _commonModeItems;
    CFRunLoopModeRef _currentMode;  // 当前模式
    CFMutableSetRef _modes;          // 所有模式
};

__CFRunLoopMode
struct __CFRunLoopMode {
    CFStringRef _name;          //mode的名字
    CFMutableSetRef _sources;  //sources0,1
    CFMutableSetRef _observers; //监听器
    CFMutableSetRef _timers; // 定时器
};
runloop是如何响应用户操作的, 具体流程是什么
  • 首先由source1把系统事件捕捉, 然后又会将事件包装成event 放入事件分发队列中,将event分发给source0中去处理
为什么只能在主线程刷新UI

我们所有的UI操作都来自UIKit这个库, 但是我们操作可能是在多线程的情况下操作, 这样就会有读写不同步的问题, 如果单纯都是用加锁的方案,系统的开销就会很大,(CPU资源, 内存, 时间片轮转), 再加上系统事件的处理也都在主线程中, 如果是在子线程刷新你UI, 我们还得同步处理事件的问题, 所以用户操作和UI要在同一个 线程,还是相对最优的方案

相关文章

  • RunLoop简易执行流程

    RunLoop 执行流程 1、通知 Observer: ,即将进入 RunLoop 2、通知 observers:...

  • Runloop

    什么是 Runloop?Runloop流程是什么?RunLoop接收几种输入源,系统默认定义了几种模式?RunLo...

  • Runloop运行状态分析

    1、先来一张图看下runloop 的运行流程: 2、具体描述:RunLoop内部的基本流程 (1)通知观察者Run...

  • iOS Runloop 流程

    iOS Runloop 基础 我们runloop 的运行流程为 1. source0 代表触摸事件的处理 可以看到...

  • iOS UI绘制

    一、UIView的绘制流程 UIView是如何到显示的屏幕上的。 这件事要从RunLoop开始,RunLoop是一...

  • iOS RunLoop都做了什么?

    RunLoop的运行流程图 RunLoop从入口函数开始都做了什么? 1.从CFRunLoopRun入口函数可以看...

  • RunLoop篇

    main函数为什么是一直运行的? RunLoop整个流程图 『RunLoop』详尽总结[http://www.co...

  • 勤奋工作(RunLoop工作)

    这个故事是从Perter每天上班开始说起的。。。(但这个不是一个好的开发流程,只是用来描述RunLoop工作而已)...

  • 新建 NSThread CFRunLoop

    runLoop 的工作流程 序号说明对应的方法 在命令行bt 可以打印堆栈信息1通知Observers:进入Loo...

  • RunLoop的概念及作用

    1.RunLoop的概念及作用 2.RunLoop的使用 3.RunLoop的相关类 4.RunLoop的工作原理...

网友评论

      本文标题:Runloop - 工作流程

      本文链接:https://www.haomeiwen.com/subject/kaobqdtx.html