美文网首页
主题六《RunLoop》

主题六《RunLoop》

作者: 东方奇迹 | 来源:发表于2020-09-19 23:19 被阅读0次

(1)、什么是RunLoop

截屏2020-07-12 下午10.10.26.png 截屏2020-07-12 下午10.12.39.png 截屏2020-07-12 下午10.13.46.png 截屏2020-07-12 下午10.15.09.png 截屏2020-07-12 下午10.16.04.png

(2)、RunLoop资料

(3)、RunLoop与线程

  • 每条线程都有唯一的一个与之对应的RunLoop对象
  • 主线程的RunLoop已经自动创建好了,子线程的RunLoop需要主动创建
  • RunLoop在第一次获取时创建,在线程结束时销毁

(4)、获得RunLoop对象

截屏2020-07-12 下午10.42.34.png 截屏2020-07-12 下午10.48.14.png 截屏2020-07-12 下午10.52.30.png

(5)、RunLoop相关类

截屏2020-07-12 下午10.56.37.png 截屏2020-08-02 下午1.14.27.png 截屏2020-08-02 下午1.18.35.png

(6)、RunLoop与相关类的关系

截屏2020-07-12 下午11.07.55.png 截屏2020-08-02 下午1.19.03.png

解析:
RunLoop启动的时候必须要选择一种运行模式,当RunLoop选择了一种运行模式之后它会做一个判断做一个检查,它要检查一下这个运行模式是否为空,主要检查这个运行模式里面有没有source有没有timer,如果一个source也没有一个timer也没有它就认为这个运行模式为空,运行模式为空是这个RunLoop就马上退出了,如果运行模式不为空,里面有source或者有timer,那么这个RunLoop就启动了,也就是说这个死循环就开起来了,它就是这样运作的。注意检查的时候只会判断source和timer,它是不会判断observer的。

model(运行模式)说明:

截屏2020-07-12 下午11.18.52.png 截屏2020-07-20 下午6.06.12.png 截屏2020-07-20 下午6.24.27.png 截屏2020-07-20 下午6.27.43.png 截屏2020-07-20 下午6.31.40.png 截屏2020-07-20 下午6.33.02.png

(7)、GCD中的定时器

截屏2020-07-20 下午8.48.54.png

(8)、CFRunLoopSourceRef

截屏2020-07-20 下午8.56.48.png 截屏2020-07-20 下午9.09.50.png

(8)、CFRunLoopObserverRef

截屏2020-07-21 上午9.47.28.png
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    //01 创建观察者
    /**
     参数说明
     第一个参数:分配存储空间 默认
     第二个参数:要监听的状态
     第三个参数:是否要持续监听 YES
     第四个参数:0
     第五个参数:block回调 当runloop状态改变的时候会调用
     */
    
    CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
        
        /**
        kCFRunLoopEntry = (1UL << 0),
        kCFRunLoopBeforeTimers = (1UL << 1),
        kCFRunLoopBeforeSources = (1UL << 2),
        kCFRunLoopBeforeWaiting = (1UL << 5),
        kCFRunLoopAfterWaiting = (1UL << 6),
        kCFRunLoopExit = (1UL << 7),
        kCFRunLoopAllActivities = 0x0FFFFFFFU
         */
        
        switch (activity) {
            case kCFRunLoopEntry:
                NSLog(@"runloop启动");
                break;
            case kCFRunLoopBeforeTimers:
                NSLog(@"runloop即将处理timer事件");
                break;
            case kCFRunLoopBeforeSources:
                NSLog(@"runloop即将处理source事件");
                break;
            case kCFRunLoopBeforeWaiting:
                NSLog(@"runloop即将进入到休眠");
                break;
            case kCFRunLoopAfterWaiting:
                NSLog(@"runloop被唤醒");
                break;
            case kCFRunLoopExit:
                NSLog(@"runloop退出");
                break;

            default:
                break;
        }
        
    });

    //02 监听runloop的状态
    /**
     参数说明
     第一个参数:runloop对象
     第二个参数:监听者
     第三个参数:监听runloop在哪种运行模式下的状态
     NSDefaultRunLoopMode == kCFRunLoopDefaultMode
     NSRunLoopCommonModes == kCFRunLoopCommonModes
     */

    CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopCommonModes);
    
    [NSTimer scheduledTimerWithTimeInterval:2.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
        
        NSLog(@"timer------");
        
    }];

}

(9)、RunLoop的运行流程

RunLoop处理逻辑-网友整理版

20160811202022658.png

每次运行runloop,你的线程的runloop会自动处理之前未处理的消息,并通知相关的观察者。runloop的时间队列具体的顺序如下:

1、通知观察者runloop已经启动
2、通知观察者任何即将要开始的定时器
3、通知观察者任何即将启动的非基于端口的源
4、处理任何准备好的非基于端口的源
5、如果基于端口的源准备好并处于等待状态,则立即处理,跳至步骤9
6、通知观察者线程进入休眠
7、将线程置于休眠直到任一下面的事件发生:

  • 某一事件达到基于端口的源
  • 定时器启动
  • runloop设置的时间已经超时
  • runloop被显式唤醒

8、通知观察者线程将被唤醒
9、判断唤醒的事件类型并处理:

  • 如果是用户定义的定时器事件,则处理并重新开始Runloop,跳至步骤2
  • 如果是一个事件源,则传递事件并重新开始Runloop,跳至步骤2
  • 如果被显式唤醒,并且还没超时,则重新开始Runloop,跳至步骤2

10、通知观察者runloop结束。

截屏2020-08-02 下午3.59.41.png 截屏2020-08-02 下午3.10.49.png 截屏2020-07-21 下午12.18.16.png 截屏2020-08-02 下午5.32.11.png

(10)、RunLoop的应用

截屏2020-07-21 下午12.22.05.png 截屏2020-07-21 下午2.23.47.png
//如何开启一个常驻线程
- (IBAction)createNewThreadBtnClick:(id)sender {
    
    //01 创建线程对象
    NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(run1) object:nil];
    //02 启动线程
    [thread start];
    
    self.thread = thread;
}
- (IBAction)goOnBtnClick:(id)sender {
    
    //让之前创建的子线程继续执行任务 主线程-子线程
    [self performSelector:@selector(run2) onThread:self.thread withObject:nil waitUntilDone:YES];
    
}
//该方法执行完毕,线程对象就会进入到死亡状态
- (void)run1 {
    NSLog(@"---run1---%@",[NSThread currentThread]);
    
    //01 子线程的runloop需要手动创建 + 启动
    //02 runloop启动之后,选择运行模式(默认),判断运行模式是否为空
    NSRunLoop *runloop = [NSRunLoop currentRunLoop];
    
    //往运行模式中添加source | timer
    /**
    [NSTimer scheduledTimerWithTimeInterval:3.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
        
        NSLog(@"tiemrunning");
        
    }];
     */
    
    //source = port | custom | selector
    //为默认的运行模式添加一个port事件,目的是让运行模式不为空,把runloop开启起来
    [runloop addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
    
    //内部会指定运行模式为默认
    [runloop run];

    NSLog(@"---end---");
}
- (void)run2 {
    NSLog(@"---run2---%@",[NSThread currentThread]);

}

(11)、RunLoop自动释放

截屏2020-07-21 下午3.38.47.png

(12)、RunLoop面试题

截屏2020-07-21 下午3.40.35.png 截屏2020-07-21 下午3.42.42.png 截屏2020-08-02 下午12.52.00.png 截屏2020-07-20 下午9.09.03.png 截屏2020-07-20 下午9.16.56.png

1、什么是RunLoop,基本作用是什么?

字面意思:

  • 运行循环、跑圈
  • 其实它内部就是do-while循环,在这个循环内部不断的处理各种任务(比如source、timer、observer)

基本作用:

  • 保持程序持续运行不退出
  • 处理APP中各种事件(触摸事件,定时器事件,Selector事件)
  • 节省CPU资源,提高程序性能,该做事的时候做事,该休息的时候休息

2、RunLoop与线程之间的关系?

  • RunLoop与线程是一一对应的关系
  • 主线程的RunLoop已经创建,子线程的RunLoop需要主动创建
  • RunLoop第一次调用时创建,线程销毁时退出

3、RunLoop五大相关类及其之间的关系?

  • CFRunloopRef
  • CFRunloopModeRef
  • CFRunloopTimerRef
  • CFRunloopSourceRef
  • CFRunloopObserverRef

RunLoop启动的时候必须要选择一种运行模式,当RunLoop选择了一种运行模式之后它会做一个判断做一个检查,它要检查一下这个运行模式是否为空,主要检查这个运行模式里面有没有source有没有timer,如果一个source也没有一个timer也没有它就认为这个运行模式为空,运行模式为空是这个RunLoop就马上退出了,如果运行模式不为空,里面有source或者有timer,那么这个RunLoop就启动了,也就是说这个死循环就开起来了,它就是这样运作的。注意检查的时候只会判断source和timer,它是不会判断observer的。

4、RunLoop的运行逻辑?

  • 1、RunLoop启动
  • 2、即将处理timer
  • 3、即将处理source
  • 4、处理source0
  • 5、如果有source1,跳转到第九步
  • 6、即将进入休眠
  • 7、休眠中,等待被唤醒
  • 8、结束休眠被唤醒
  • 9、处理唤醒时收到的消息,timer消息和source1消息,然后跳转到第二步
  • 10、退出RunLoop

5、RunLoop的应用有哪些?

1、 开启一个常驻线程,让子线程不被消亡,等待其它线程发来消息,处理消息事件

(1)在子线程中开启一个定时器
(2)在子线程中进行一些长期的监控

2、 可以控制定时器在特定模式下执行

3、 可以让某些事件(行为、任务)在特定模式下执行

4、 添加observer监听RunLoop状态

5、 自动释放池的创建与销毁

(1)自动释放池第一次创建:当RunLoop启动的时候
(2)自动释放池最后一次销毁:当RunLoop退出的时候
(3)自动释放池其它时间的创建和销毁:当RunLoop将要进入休眠的时候,会把之前的自动释放池释放掉,重新创建一个新的自动释放池

相关文章

网友评论

      本文标题:主题六《RunLoop》

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