• OC-run loop


    什么是run loop

    运行回路
    就是一个不停处理消息 如果有消息就醒来处理 消息就去休息的循环
    可以这么理解 假设RunLoop就是一个对象 这个对象有需要处理的消息和事件 然后他提供了一个入口函数 参数是一个线程 他会放一个线程进来处理 会一直处在 “接受消息->等待->处理”的循环中 直到这个循环结束(比如quit消息)

    作用

    主要是为了保证程序持续运行和接受用户输入 并且处理各种事件

    数据结构

    CFRunLoop是NSRunLoop的上层封装 所以一般研究CFRunLoop
    在这里插入图片描述
    在这里插入图片描述

    CFRunLoop是和Thread(线程)一一绑定的

    NSRunLoopCommonModes本质是一个字符串 结构上好像类是于一个数组
    NSRunLoopCommonModes 包含了NSDefaultRunLoopMode UITrackingRunLoopMode UIInitializationRunLoopMode
    可以手动将自己的mode加入到NSRunLoopCommonModes中

    CFRunLoop(一个结构体)

    反正就是有一个RunLoop对象 然后一个进程会对应一个RunLoop对象 再往RunLoop里吗放timer什么

    struct __CFRunLoop {
        CFRuntimeBase _base;
        pthread_mutex_t _lock;			/* locked for accessing mode list */
        __CFPort _wakeUpPort;			// used for CFRunLoopWakeUp 通过这个来唤醒runloop
        Boolean _unused;
        volatile _per_run_data *_perRunData;              // reset for runs of the run loop
        pthread_t _pthread; //该线程和RunLoop是一一对应的关系 线程的底层都是pthread_t
        uint32_t _winthread;
        CFMutableSetRef _commonModes; // 存放的commonModes集合
        CFMutableSetRef _commonModeItems;//timer source oberver作为item被存放在这里
        CFRunLoopModeRef _currentMode;
        CFMutableSetRef _modes;
        struct _block_item *_blocks_head;
        struct _block_item *_blocks_tail;
        CFAbsoluteTime _runTime;
        CFAbsoluteTime _sleepTime;
        CFTypeRef _counterpart;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    CFRunLoopMode 这个和上面那个是不是一个东西?

    在这里存放了_sources0和_sources1 ,_timers,_observers

    struct __CFRunLoopMode {
        CFRuntimeBase _base;
        pthread_mutex_t _lock;	/* must have the run loop locked before locking this */
        CFStringRef _name;
        Boolean _stopped;
        char _padding[3];
        CFMutableSetRef _sources0;
        CFMutableSetRef _sources1;
        CFMutableArrayRef _observers;
        CFMutableArrayRef _timers;
        CFMutableDictionaryRef _portToV1SourceMap;
        __CFPortSet _portSet;
        CFIndex _observerMask;
    #if USE_DISPATCH_SOURCE_FOR_TIMERS
        dispatch_source_t _timerSource;
        dispatch_queue_t _queue;
        Boolean _timerFired; // set to true by the source when a timer has fired
        Boolean _dispatchTimerArmed;
    #endif
    #if USE_MK_TIMER_TOO
        mach_port_t _timerPort;
        Boolean _mkTimerArmed;
    #endif
    #if DEPLOYMENT_TARGET_WINDOWS
        DWORD _msgQMask;
        void (*_msgPump)(void);
    #endif
        uint64_t _timerSoftDeadline; /* TSR */
        uint64_t _timerHardDeadline; /* TSR */
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    应用从操作系统(窗口服务器)中接受鼠标点击等事件的消息,并将其转到相应的例行程序来处理,如此反复,这样的过程称为运行回路
    比如说当button被点击的时候操作系统会发出Action消息 然后UIApplicaion类会根据这个消息选择对应的处理对象发送给他
    主运行回路会在启动事件处理方法时生成一个自动释放池

    RunLoop结构

    一个RunLoop可以有若干个mode mode包含source time oberver
    每一次调用RunLoop主函数只能指定其中一个Mode 这个Mode就是CurrentMode 要切换Mode只能退出Loop 重新制定 目的是分割不同mode的source time oberver

    在这里插入图片描述

    Source

    分为Source0和Source1
    source0不具备主动唤醒能力 source0是可以创建API接口什么的 添加到当前runloop中
    基于port端口事件 可以主动唤醒线程 并且source1是没有定义API接口供我们操作

    NSRunLoop和CFRunLoopRef

    CFRunLoop是NSRunLoop的上层封装

    CFRunLoopRef 是在 CoreFoundation 框架内的,它提供了纯 C 函数的 API 线程安全
    NSRunLoop 是基于 CFRunLoopRef 的封装 线程不安全

    线程

    线程和RunLoop是一一对应的 这是由于会创建一个全局的Dictionary(static CFMutableDictionaryRef loopsDic) 用来存储RunLoop和thread
    比如在通过_CFRunLoopGet获取RunLoop的时候 如果是第一次创建 也就是loopsDic是空的 没有 就会创建一个

    loopsDic = CFDictionaryCreateMutable();
    CFRunLoopRef mainLoop = _CFRunLoopCreate();
    CFDictionarySetValue(loopsDic, pthread_main_thread_np(), mainLoop);//然后将这个loop和主线程绑定
    
    • 1
    • 2
    • 3

    如果有 就会在这个dictionary根据thread作为key 去匹配 RunLoop

    系统会自动开启主线程的RunLoop 保证程序不会提出
    子线程的RunLoop需要手动开启

    通过 pthread_main_thread_np() 或 [NSThread mainThread] 来获取主线程;也可以通过 pthread_self() 或 [NSThread currentThread] 来获取当前线程

    方法

    //OC方法
    NSRunLoop *runloop = [NSRunLoop currentRunLoop]; // 获得当前线程的RunLoop对象 此时会创建RunLoop
    [NSRunLoop mainRunLoop]; // 获得主线程的RunLoop对象
    
    //C语言方法
    CFRunLoopGetCurrent(); // 获得当前线程的RunLoop对象
    CFRunLoopGetMain(); // 获得主线程的RunLoop对象
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
  • 相关阅读:
    算法通关村16关 | 滑动窗口如此简单
    基于Apache组件,分析对象池原理
    Wayland introduce
    戴建业作品集读书笔记
    051_末晨曦Vue技术_处理边界情况之provide和inject依赖注入
    什么是M365 Manager Plus?
    [jetson][转载]jetson上安装pycharm
    文心一言与GPT-4全面对比——人工智能语言模型的新纪元
    博客摘录「 hyperf使用jwt的redis储存驱动实现用户token认证」2024年4月9日
    计算机专业毕业设计项目推荐10-饮食搭配平台(Go+微信小程序+Mysql)
  • 原文地址:https://blog.csdn.net/qq_43535469/article/details/126173367