RunLoop使用详情(视频讲解)

1.讲讲RunLoop,项目中有用到吗?

RunLoop顾名思义就是程序在运行过程中循环做一些事情.如果没有RunLoop的话,程序运行结束以后就会马上退出的.而我们OC的main函数系统自动为我们创建了RunLoop函数,所以程序并不会马上退出,而是保持运行状态,监听用户的相关操作.

RunLoop的基本作用:

  1. 保持程序的持续运行;
  2. 处理App中的各种事件(比如触摸事件,定时器事件等)
  3. 节约CPU资源,提高程序性能.该做事的时候做事,该休息的时候休息.

RunLoop 的应用范畴:

  1. 定时器,
  2. GCD Async Main Queue,
  3. 事件响应,
  4. 手势识别,
  5. 界面刷新,
  6. 网络请求,
  7. AutoreleasePool,
  8. performSelector:on Thread

RunLoop 对象:

ios中有2套API来访问和使用RunLoop:

  1. 方式一:Foundation框架中的:NSRunLoop
  2. 方式二:Core Foundation框架中的:CFRunLoopRef(开源的)

  NSRunLoop和CFRunLoopRef都代表着RunLoop对象,而 NSRunLoop是对CFRunLoopRef的一层OC封装.

  获取RunLoop的对象:

     [NSRunLoop currentRunLoop];//获取当前线程的RunLoop

     [NSRunLoop mainRunLoop];//获取主线程的RunLoop

RunLoop 相关的五个类: 

  1. CFRunLoopRef--->

    NSRunLoop对象是OC对象,是对CFRunLoopRef的封装,可以通过getCFRunLoop方法获取其对应的CFRunLoopRef对象。注意,NSRunLoop不是线程安全的,但CFRunLoopRef是线程安全的

  2. CFRunLoopModeRef-->

    NSRunLoop对象是一系列RunLoopMode的集合,每个mode包括有这个模式下所有的Source源、Timer源和观察者。每次RunLoop调用的时候都只能调用其中的一个mode,接收这个mode下的源,通知这个mode下的观察者。这样设计的主要目的就是为了隔离各个模式下的源和观察者,使其不相互影响,model有一下常用的五种:

  3.  2.1.kCFRunLoopDefaultMode:

  4. ​​​​​​​ App默认的mode,通常主线程就是在这个mode下运行的

     2.2.UITrackingRunLoopMode:

  5. 界面跟踪时的mode,一般用于ScrollView滚动的时候追踪的,保证滑动的时候不受其他model的影响

    2.3.UIInitializationRunLoopMode:

  6. 在刚启动 App 时进入的第一个 Mode,启动完成后就不再使用

    2.4.GSEventReceiveRunLoopMode:

  7. 接受系统事件的内部 Mode,一般用不到

    2.5.kCFRunLoopCommonModes:

  8. 占位mode,可以向其中添加其他mode用以检测多个mode的事件

  9. 3.​​​​​​​​​​CFRunLoopSourceRef--->事件源产生的地方

  10. ​​​​​​​4.CFRunLoopTimerRef-->是基于事件的触发器,其中包含一段时间长度、延期容忍度和一个函数指针(回调方法)。当其加入到RunLoop中时,RunLoop会注册一个时间点,当到达这个时间点后,会触发对应的事件。​​​​​​​

  11. 5.CFRunLoopObserverRef-->RunLoop的观察者。每个观察者都可以观察RunLoop在某个模式下事件的触发并处理

    kCFRunLoopEntry:即将进入runLoop

    kCFRunLoopBeforeTimers:即将处理Timer

    kCFRunLoopBeforeSources:即将处理Source

    kCFRunLoopBeforeWaiting:即将进入休眠

    kCFRunLoopAfterWaiting:刚从休眠中被唤醒

    kCFRunLoopExit:即将退出RunLoop

CFRunLoopModeRef代表RunLoop的运行模式

  1. 一个RunLoop包含若干个Mode,每个Mode又包含若干个Source0/ Source1/Timer/Observer
  2. RunLoop启动时只能选择其中一个Mode,作为currentMode
  3. 如果需要切换Mode,只能退出当前Loop,在重新选择一个Mode进入(这样做的好处是:不同组的Source0/ Source1/Timer/Observer能分隔开,互不影响)
  4. 如果Mode中没有任何Source0/ Source1/Timer/Observer,RunLoop会立马退出.

mode​​​​​​​的分别处理的事件:

  1.  Source0:处理触摸事件/perform Selectors
  2. Source1:处理基于Port的线程通信
  3. Timer:处理定时器/NSTimer
  4. Observer:处理监听器/用于监听RunLoop的状态.

总结:

     首先CFRunloopRef这个对象里面有一个CFMutableSetRef _modes这个集合,而_modes这个集合里面装着一堆CFRunLoopModeRef model,当然有其中一个model代表当前的model(_currentModel).而CFRunLoopModeRef里面又装着很多CFMutableSetRef _sources0集合,CFMutableSetRef _sources1集合(sources0和sources1这个集合里面装着一堆CFRunLoopSourceRef对象),CFMutableArrayRef _observers集合(这个 集合里面装着一堆CFRunLoopObserverRef对象),tCFMutableArrayRef _timers集合(这个集合里面装着一堆CFRunLoopTimerRef对象)

2.RunLoop内部执行逻辑?

  1.  通知Observers ,进入Loop;
  2. 通知Observers,即将处理Timers;
  3. 通知Observers即将处理 Sources;
  4. 处理Blocks;
  5. 处理 Source0(可能会再次处理Blocks);
  6. 如果存在Source1,就会跳转到第8步处理Source1;
  7. 通知Observers开始休眠(一旦开始睡眠 了就需要等待消息进行唤醒);
  8. 如果被某个消息唤醒了就通知Observers结束休眠​,开始处理相应的事件--->1.如果是Timer唤醒了就处理Timer;2.如果是GCD唤醒了就处理CGD;3.如果是Source1唤醒了就处理Source1.
  9. 处理Blocks->重新再处理一遍block;
  10. 根据当前的执行结果,决定如何操作是重新回到第2步执行还是直接退出Loop.
  11. 如果需要直接退出runloop,则通知Observers退出Loop

RunLoop使用详情(视频讲解)_第1张图片​​​​​​​

源码解析

3.RunLoop和线程的关系?

  1. 每条线程都有唯一的一个与之对应的RunLoop对象;
  2. RunLoop保存在一个全局的Dictionary里,线程作为key,RunLoop作为Value(源码可以证明);
  3. 线程刚创建时并没有RunLoop对象,RunLoop会在第一次获取它时创建;
  4. RunLoop会在线程结束时候销毁.

4.timer和RunLoop的关系?

/**
     第一种方法:
     1.此方法的创建定时器默认会加到了NSRunLoop中,并设置运行模式为默认.
     2.如是想在子线程中开启NSRunLoop,需要手动开启:
     NSRunLoop*runllop=[NSRunLoop currentRunLoop];等到线程销毁的时候currentRunLoop的对象也随之销毁;
     3.在子线程的定时器,需要手动加入runLoop,不要忘记调用run方法
     */
    
    [NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(startTime) userInfo:nil repeats:YES];


    /**
     第二种方法:
     1.此方法创建需要手动将定时器添加到 NSRunLoop中,指定的运行模式是default,但是有滚动事件的时候,定时器就会停止工作.
     解决方案:更改NSRunLoop的运行模式.UITrackingRunLoopMode界面追踪,此模式只有发生滚动事件的时候才会开启定时器.若是任何时候都会开启定时器:NSRunLoopCommonModes(NSRunLoopCommonModes=NSDefaultRunLoopMode+UITrackingRunLoopMode).凡是添加到NSRunLoopCommonModes中的事件都会被同时添加到CommonMode的运行模式上的.
     */
    NSTimer*timer=[NSTimer timerWithTimeInterval:3.0 target:self selector:@selector(startTime) userInfo:nil repeats:YES];
    //下面这三种情况根据实际情况加入RunLoop
    [[NSRunLoop currentRunLoop]addTimer:timer forMode:NSDefaultRunLoopMode];
    [[NSRunLoop currentRunLoop]addTimer:timer forMode:NSRunLoopCommonModes];

    [[NSRunLoop currentRunLoop]addTimer:timer forMode:UITrackingRunLoopMode];

5.程序中添加每3秒响应一次的NSTimer,当拖动tableview时候timer可能无法响应要怎么解决?

   将Timer添加到CommonModes类型里面.

6.RunLoop是怎么响应用户操作的,具体流程是什么样的?

7.说说RunLoop的几种状态?

8.RunLoop的model作用是什么?

视频讲解:

视频一:runLoop使用详情,视频讲解(一)-IOS文档类资源-CSDN下载

视频二:runLoop使用详情,视频讲解(二)-IOS文档类资源-CSDN下载

视频三:runLoop使用详情,视频讲解(三)-IOS文档类资源-CSDN下载

视频四:runLoop使用详情,视频讲解(四)-IOS文档类资源-CSDN下载

视频五:runLoop使用详情,视频讲解(五)-IOS文档类资源-CSDN下载

视频六:runLoop使用详情,视频讲解(六)-IOS文档类资源-CSDN下载

视频七:runLoop使用详情,视频讲解(七)-IOS文档类资源-CSDN下载

视频八:runLoop使用详情,视频讲解(八)-IOS文档类资源-CSDN下载

视频九:runLoop使用详情,视频讲解(九)-IOS文档类资源-CSDN下载

你可能感兴趣的:(OC,objective-c,ios,RunLoop,RunLoop面试题)