美文网首页
Runloop源码分析(1)——初探

Runloop源码分析(1)——初探

作者: 无悔zero | 来源:发表于2021-01-20 19:35 被阅读0次

首先了解一下RunloopRun是运行,Loop是循环。

  • 默认情况下主线程的RunLoop原理:

我们在启动一个iOS程序的时候,系统会调用创建项目时自动生成的main.m的文件。main.m文件如下所示:

int main(int argc, char * argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

其中UIApplicationMain函数内部帮我们开启了主线程的RunLoopUIApplicationMain内部拥有一个无线循环的代码。上边的代码中开启RunLoop的过程可以简单的理解为如下代码(实际当然不是这样):

int main(int argc, char * argv[]) {        
    BOOL running = YES;
    do {
        // 执行各种任务,处理各种事件
    } while (running);

    return 0;
}

从上边可看出,程序一直在do-while循环中执行,所以UIApplicationMain函数一直没有返回,我们在运行程序之后程序不会马上退出,会保持持续运行状态。

  • RunLoop实际上是一个对象,这个对象在循环中用来处理程序运行过程中出现的各种事件(比如说触摸事件、UI刷新事件、定时器事件、Selector事件),从而保持程序的持续运行;而且在没有事件处理的时候,会进入睡眠模式,从而节省CPU资源,提高程序性能。

从上图中可以看出,RunLoop就是线程中的一个循环,RunLoop在循环中会不断检测,通过Input sources(输入源)和Timer sources(定时源)两种来源等待接受事件;然后对接受到的事件通知线程进行处理,并在没有事件的时候进行休息。

{\large\text{作者:奔跑吧小蚂蚁 链接:https://www.jianshu.com/p/6929ea3907cf 来源:简书 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。}}

Runloop的特点:

  1. RunLoop和线程是绑定在一起的,每条线程都有唯一一个与之对应的RunLoop
  2. 不能创建RunLoop,但是可以获取系统提供的RunLoop
  3. 主线程的RunLoop是由系统自动创建好的,在应用程序启动的时候会自动完成启动,而子线程中的RunLoop需要手动获取并启动。

{\large\text{作者:夜幕降临耶 链接:https://www.jianshu.com/p/fab2b3b2ae8e 来源:简书 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。}}

所以要注意主线程默认开启Runloop,子线程默认不开启,如下面例子:

dispatch_async(dispatch_get_global_queue(0, 0), ^{
    NSLog(@"1");
    [[NSRunLoop currentRunLoop] run];//子线程runloop默认不开启
    [self performSelector:@selector(test) withObject:nil afterDelay:0];//内部是创建timer执行
    NSLog(@"3");//不开启子线程的runloop就只打印1,3
});
  • Runloop的结构

平常使用的NSRunloop内部其实就是CFRunloop

struct __CFRunLoop {
    CFRuntimeBase _base;
    pthread_mutex_t _lock;//获取mode列表的锁  /* locked for accessing mode list */
    //mach_port
    __CFPort _wakeUpPort;//唤醒端口 // used for CFRunLoopWakeUp
    Boolean _unused;
    volatile _per_run_data *_perRunData;//重置RunLoop数据   // reset for runs of the run loop
    pthread_t _pthread;//RunLoop所对应的线程
    uint32_t _winthread;
    CFMutableSetRef _commonModes;//标记为common的mode的集合
    CFMutableSetRef _commonModeItems;//commonMode的item集合
    CFRunLoopModeRef _currentMode;//当前的mode
    CFMutableSetRef _modes;//存储的是CFRunLoopModeRef
    struct _block_item *_blocks_head;// _block_item链表表头指针
    struct _block_item *_blocks_tail;// _block_item链表表尾指针
    CFAbsoluteTime _runTime;//运行时间点
    CFAbsoluteTime _sleepTime;//睡眠时间点
    CFTypeRef _counterpart;
};
struct __CFRunLoopMode {
    CFRuntimeBase _base;
    pthread_mutex_t _lock;//锁, 必须runloop加锁后才能加锁 /* must have the run loop locked before locking this */
    CFStringRef _name;//mode的名称
    Boolean _stopped;//mode是否停止
    char _padding[3];
    CFMutableSetRef _sources0;//sources0事件
    CFMutableSetRef _sources1;//sources1事件
    CFMutableArrayRef _observers;//observers事件
    CFMutableArrayRef _timers;//timers事件
    CFMutableDictionaryRef _portToV1SourceMap;//字典  key是mach_port_t,value是CFRunLoopSourceRef
    __CFPortSet _portSet;//保存所有需要监听的port,比如_wakeUpPort,_timerPort都保存在这个数组中
    CFIndex _observerMask;
#if USE_DISPATCH_SOURCE_FOR_TIMERS
    dispatch_source_t _timerSource;//GCD定时器
    dispatch_queue_t _queue;//GCD队列
    Boolean _timerFired;// 当定时器触发时设置为true // 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 */
};
  • 应用

最常见的例子应该是定时器了:

NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
    NSLog(@"1");
}];
[[NSRunLoop currentRunLoop] addTimer:timer forMode: NSRunLoopCommonModes];

下一篇:Runloop获取

相关文章

  • Runloop源码分析(1)——初探

    首先了解一下Runloop,Run是运行,Loop是循环。 默认情况下主线程的RunLoop原理:我们在启动一个i...

  • RunLoop学习资料

    非常好的runloop学习系列 CoreFoundation源码 RunLoop系列之源码分析 关于Runloop...

  • 36.iOS底层学习之RunLoop

    本章提纲:1、RunLoop基础知识2、RunLoop的数据结构3、RunLoop的相关源码分析4、RunLoop...

  • RunLoop 源码分析

    此篇主要分析 RunLoop 的源码,对源码的注释在仓库中。 分析源码我主要采用的是: RunLoop 相关的结构...

  • socket基本的API使用

    1.socket初探 2.socket分析 3.socket内核源码分析 系统调用的过程: 1.int socke...

  • 【高级iOS】autoreleasepool源码分析,并与run

    【高级iOS】autoreleasepool源码分析,并与runloop的关系

  • iOS:RunLoop详解

    1、RunLoop初探 1.1、RunLoop是什么? RunLoop从字面上来说是跑圈的意思,如果这样理解不免有...

  • Android 技术干货系列(一)

    目录 热门技术 View 代码封装 源码分析 精进之路 1 热门技术 Kotlin初探 Kotlin成了Googl...

  • 15-RunLoop-02

    一、RunLoop运行逻辑 1.源码分析:精简版(保留了核心代码) 2.休眠细节 二、RunLoop在实际开发中的...

  • iOS源码分析(1)——RunLoop

    NSRunLoop 是基于 CFRunLoopRef 的OC封装,提供了面向对象的 API,但不是线程安全的,CF...

网友评论

      本文标题:Runloop源码分析(1)——初探

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