RunLoop本质相关面试问题

2019-11-01  本文已影响0人  骑着毛驴走起来

一、什么是RunLoop?

RunLoop是通过内部维护的事件循环来对事件/消息进行管理的一个对象。
1、没有消息需要处理时,休眠以避免资源占有。
2、有消息需要处理时,立刻被唤醒。

屏幕快照 2019-09-15 下午4.58.42.png 屏幕快照 2019-09-15 下午5.01.46.png

二、RunLoop的数据结构

NSRunLoop是CFRunLoop的封装,提供了面向对象的API。
开源代码地址:http://opensource.apple.com/tarballs/CF/CF-855.17.tar.gz
1、CFRunLoop
(1)、pthread:一一对应(RunLoop和线程的关系)
(2)、currentModel:CFRunLoopModel

屏幕快照 2019-09-15 下午5.22.03.png

(3)、models:NSMutableSet<CFRunLoopModel*>

屏幕快照 2019-09-15 下午5.28.29.png

(4)、commonModels:NSMutableSet<NSString*>
1>、CommonModel不是实际存在的一种Model。
2>、是同步Source/Timer/Observer到多个Model中的一种技术方案。

(5)、commonModelItems:包含Observer、Timer、Source

2、CFRunLoopModelItems

3、Source/Timer/Observer
1>、CFRunLoopSource
source0:需要手动唤醒线程。
source1:具备唤醒线程的能力。

2>、CFRunLoopTimer
基于事件的定时器,和NSTimer是toll-free bridged的。

3>、CFRunLoopObserver
观测时间点
KCFRunLoopEntry
KCFRunLoopBeforeTimers
KCFRunLoopBeforeSources
KCFRunLoopBeforeWaiting
KCFRunLoopAfterWaiting
KCFRunLoopExit

屏幕快照 2019-09-15 下午5.26.49.png

三、RunLoop事件循环机制的实现

屏幕快照 2019-09-15 下午5.54.49.png 屏幕快照 2019-09-15 下午5.57.03.png

四、RunLoop与NSTimer

滑动TableView的时候,我们的定时器还会生效吗?
Model发生切换,从KCFRunLoopDefaultModel切换到UITrackingRunLoopModel

五、RunLoop与多线程

1、咋样实现一个常驻线程
(1)、为当前线程开启一个RunLoop。
(2)、向该RunLoop中添加一个Port/Source等维持RunLoop的事件循环。
(3)、启动该RunLoop。
2、RunLoop和线程关系
(1)、runloop与线程是一一对应的,一个runloop对应一个核心的线程,为什么说是核心的,是因为runloop是可以嵌套的,但是核心的只能有一个,他们的关系保存在一个全局的字典里。
(2)、runloop是来管理线程的,当线程的runloop被开启后,线程会在执行完任务后进入休眠状态,有了任务就会被唤醒去执行任务。
(3)、runloop在第一次获取时被创建,在线程结束时被销毁。
(4)、对于主线程来说,runloop在程序一启动就默认创建好了。
(5)、对于子线程来说,runloop是懒加载的,只有当我们使用的时候才会创建。

    dispatch_queue_t queue = dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        [self performSelector:@selector(timerAction) withObject:nil afterDelay:1];
        [[NSRunLoop currentRunLoop] run];
    });

(6)、子线程中使用定时器,需将定时器添加至RunLoop中,确保子线程的runloop被创建,不然定时器不会回调。

  dispatch_queue_t queue = dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_SERIAL);
    
    dispatch_async(queue, ^{
        
        //此种方式创建的timer已经添加到NSRunloop中了
        NSTimer *timer1 =[NSTimer scheduledTimerWithTimeInterval:0 target:self selector:@selector(timerAction) userInfo:nil repeats:YES];
        [[NSRunLoop currentRunLoop] run];
        
        
        //此种方式创建的timer没有添加至runloop中
        NSTimer *timer2 = [NSTimer timerWithTimeInterval:1.0f target:self selector:@selector(timerAction) userInfo:nil repeats:YES];
        [[NSRunLoop currentRunLoop] addTimer:timer2 forMode:NSDefaultRunLoopMode];
        [[NSRunLoop currentRunLoop] run];

    });
屏幕快照 2019-09-15 下午6.19.44.png
上一篇 下一篇

猜你喜欢

热点阅读