美文网首页
iOS NSRunLoop

iOS NSRunLoop

作者: 青椒辣不辣 | 来源:发表于2020-12-14 17:18 被阅读0次
  • Core Foundation中关于RunLoop的5个类

  • CFRunLoopRef
  • CFRunLoopModeRef
  • CFRunLoopSourceRef
  • CFRunLoopTimerRef
  • CFRunLoopObserverRef
  • CFRunLoopModeRef(系统默认注册了5个Mode)

  • kCFRunLoopDefaultMode:App的默认Mode,通常主线程是在这个Mode下运行
  • UITrackingRunLoopMode:界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响
  • UIInitializationRunLoopMode: 在刚启动 App 时第进入的第一个 Mode,启动完成后就不再使用
  • GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,通常用不到
  • kCFRunLoopCommonModes: 这是一个占位用的Mode,不是一种真正的Mode

\color{rgb(0 ,139, 139)}{获取RunLoop}

-(void)task{
    NSLog(@"%s",__func__);
    
    NSLog(@"currentThreadaaaaaaaaa-->%@",[NSThread currentThread]);
    
    //1.获得当前线程对应的runloop对象
    NSRunLoop *currentRunloop = [NSRunLoop currentRunLoop];
    //2.获得主线程对应的runloop对象--->主runloop
    NSRunLoop *mainRunloop =[NSRunLoop mainRunLoop];
    NSLog(@"task_currentRunloopaaa-->%p",currentRunloop);
    NSLog(@"task_mainRunloopaaaaaa-->%p",mainRunloop);
    
    
    //1.获得当前线程对应的runloop对象
    CFRunLoopRef currentRunloopRef = CFRunLoopGetCurrent();
    //2.获得主线程对应的runloop对象--->主runloop
    CFRunLoopRef  mainRunloopRef = CFRunLoopGetMain();
    NSLog(@"task_currentRunloopRef-->%p",currentRunloopRef);
    NSLog(@"task_mainRunloopRefaaa-->%p",mainRunloopRef);
    
    
    //转换 NSRunloop --> CFRunLoopRef
    NSLog(@"task_NSRunloop --> CFRunLoopRef == %p--%p",currentRunloopRef,currentRunloop.getCFRunLoop);
    NSLog(@"task_NSRunloop --> CFRunLoopRef == %p--%p",mainRunloopRef,mainRunloop.getCFRunLoop);
    
}

-[RJTextTwoViewController task]
currentThreadaaaaaaaaa--><NSThread: 0x6000002785c0>{number = 8, name = (null)}
task_currentRunloopaaa-->0x60000333edc0
task_mainRunloopaaaaaa-->0x6000033346c0
task_currentRunloopRef-->0x600002b23300
task_mainRunloopRefaaa-->0x600002b20500
task_NSRunloop --> CFRunLoopRef == 0x600002b23300--0x600002b23300
task_NSRunloop --> CFRunLoopRef == 0x600002b20500--0x600002b20500

\color{rgb(0 ,139, 139)}{CFRunloopObserver}

    //1.创建监听者
    //CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(分配存储空间, 告知要监听的是哪种状态, 是否持续监听runloop状态, 优先级 0, activity runloop当前的状态);
    CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
        switch (activity) {
            case kCFRunLoopEntry:NSLog(@"进入");break;
            case kCFRunLoopBeforeTimers:NSLog(@"即将处理timer事件");break;
            case kCFRunLoopBeforeSources:NSLog(@"将处理soure事件");break;
            case kCFRunLoopBeforeWaiting:NSLog(@"即将进入休眠");break;
            case kCFRunLoopAfterWaiting:NSLog(@"被唤醒");break;
            case kCFRunLoopExit:NSLog(@"runloop退出");break;
            default:break;
        }
    });
    //2.给对应的runloop添加监听者并且制定监听的是哪种运行模式
    //CFRunLoopAddObserver(CFRunLoopGetCurrent()(runloop对象本身),observer(监听者(观察者)), kCFRunLoopDefaultMode(runloop的运行模式));
    CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopCommonModes);

\color{rgb(0 ,139, 139)}{总结}

 概念:进程|线程|多线程|串行|并行
 实现方案:
    pthread  了解(如何创建线程)
    NSThread  创建线程|状态(新建*就绪*运行*阻塞*死亡)|线程安全(互斥锁-线程同步)|通信
    GCD      
            概念:队列(串行2+并发2) + 任务(异步函数+同步函数)
            各种队列和各种任务执行方式的组合情况(4+2)
            开线程:1)异步函数 2)不能是主队列
            常用函数:一次性代码(单例模式)|栅栏函数(控制并发队列中任务的执行顺序)
                    延迟执行|队列组|快速迭代(apply)
    NSOperation 概念:队列+ 操作
                封装操作(3)
                开线程:队列(非主队列) + 操作
                    1)封装操作-->2)创建非主队列-->3)添加操作到队列中
                常用操作:取消|暂停|恢复|苹果官方建议
                属性:最大并发数 == 1 串行队列
                线程间通信(提交任务到主队列主队列)
    单例模式    1)只分配一次存储空间(once)2)提供类方法
    多图下载示例  二级缓存结构|SDWebImage框架内部实现原理
    SDWebImage  面试前一定要再看一遍
    Runloop     概念|作用|线程和runloop |获得对象
                runloop相关类(mode runloop source timer observer)
                runloop内部的处理逻辑
                runloop的应用(常驻线程)

//自动释放池什么时候释放?
 当runloop启动进入的时候回创建一个自动释放池
 当runloop退出的时候会吧自动释放池销毁
 当runloop即将休眠的时候会先把之前的自动释放池销毁然后重新创建一个新的

相关链接: iOS 定时器

    1. Runloop基础知识
        1)字面意思
            a 运行循环
            b 跑圈

        2)基本作用(作用重大)
            a 保持程序的持续运行(ios程序为什么能一直活着不会死)
            b 处理app中的各种事件(比如触摸事件、定时器事件(NSTimer)、selector事件(performSelector)
            c 节省CPU资源,提高程序性能,有事情就做事情,没事情就休息

        3)重要说明
            (1)如果没有Runloop,那么程序一启动就会退出,什么事情都做不了。
            (2)如果有了Runloop,那么相当于在内部有一个死循环,能够保证程序的持续运行
            (2)main函数中的Runloop
                    a 在UIApplication函数内部就启动了一个Runloop,该函数返回一个int类型的值
                    b 这个默认启动的Runloop是跟主线程相关联的

        4)Runloop对象
            (1)在iOS开发中有两套api来访问Runloop
                a.foundation框架【NSRunloop】
                b.core foundation框架【CFRunloopRef】
            (2)NSRunLoop和CFRunLoopRef都代表着RunLoop对象,它们是等价的,可以互相转换
            (3)NSRunLoop是基于CFRunLoopRef的一层OC包装,所以要了解RunLoop内部结构,需要多研究CFRunLoopRef层面的API(Core Foundation层面)


        5)Runloop参考资料
            (1)苹果官方文档
            https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html
            (2)CFRunLoopRef开源代码下载地址:
            http://opensource.apple.com/source/CF/CF-1151.16/

        6)Runloop与线程
            (1)Runloop和线程的关系:一个Runloop对应着一条唯一的线程
                问题:如何让子线程不死
                回答:给这条子线程开启一个Runloop
            (2)Runloop的创建:主线程Runloop已经创建好了,子线程的runloop需要手动创建
            (3)Runloop的生命周期:在第一次获取时创建,在线程结束时销毁

        7)获得Runloop对象
            (1)获得当前Runloop对象
                //01 NSRunloop
                NSRunLoop * runloop1 = [NSRunLoop currentRunLoop];
                //02 CFRunLoopRef
                CFRunLoopRef runloop2 =   CFRunLoopGetCurrent();

            (2)拿到当前应用程序的主Runloop(主线程对应的Runloop)
                //01 NSRunloop
                NSRunLoop * runloop1 = [NSRunLoop mainRunLoop];
                //02 CFRunLoopRef
                CFRunLoopRef runloop2 =   CFRunLoopGetMain();

            (3)注意点:开一个子线程创建runloop,不是通过alloc init方法创建,而是直接通过调用currentRunLoop方法来创建,它本身是一个懒加载的。
            (4)在子线程中,如果不主动获取Runloop的话,那么子线程内部是不会创建Runloop的。可以下载CFRunloopRef的源码,搜索_CFRunloopGet0,查看代码。
            (5)Runloop对象是利用字典来进行存储,而且key是对应的线程Value为该线程对应的Runloop。

    
    2. Runloop相关类
        1)Runloop运行原理图
        2)五个相关的类
            a.CFRunloopRef
            b.CFRunloopModeRef【Runloop的运行模式】
            c.CFRunloopSourceRef【Runloop要处理的事件源】
            d.CFRunloopTimerRef【Timer事件】
            e.CFRunloopObserverRef【Runloop的观察者(监听者)】

        3)Runloop和相关类之间的关系图
    
    
        4)CFRunloopModeRef
            Runloop要想跑起来,它的内部必须要有一个mode,这个mode里面必须有source\observer\timer,至少要有其中的一个。
            01.CFRunloopModeRef代表着Runloop的运行模式
            02.一个Runloop中可以有多个mode,一个mode里面又可以有多个source\observer\timer等等
            03.每次runloop启动的时候,只能指定一个mode,这个mode被称为该Runloop的当前mode
            04.如果需要切换mode,只能先退出当前Runloop,再重新指定一个mode进入
            05.这样做主要是为了分割不同组的定时器等,让他们相互之间不受影响
            06.系统默认注册了5个mode
                a.kCFRunLoopDefaultMode:App的默认Mode,通常主线程是在这个Mode下运行
                b.UITrackingRunLoopMode:界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响
                c.UIInitializationRunLoopMode: 在刚启动 App 时第进入的第一个 Mode,启动完成后就不再使用
                d.GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,通常用不到
                e.kCFRunLoopCommonModes: 这是一个占位用的Mode,不是一种真正的Mode


        5)CFRunloopTimerRef
            (1)NSTimer相关代码
            (2)GCD中的定时器
                
        6)CFRunloopSourceRef
            (1)是事件源也就是输入源,有两种分类模式;
                  a.一种是按照苹果官方文档进行划分的
                  b.另一种是基于函数的调用栈来进行划分的(source0和source1)。
            (2)具体的分类情况
                a.以前的分法
                    Port-Based Sources
                    Custom Input Sources
                    Cocoa Perform Selector Sources
                b.现在的分法
                    Source0:非基于Port的
                    Source1:基于Port的
            (3)可以通过打断点的方式查看一个方法的函数调用栈

        7)CFRunLoopObserverRef
            (1)CFRunLoopObserverRef是观察者,能够监听RunLoop的状态改变
            (2)如何监听
        
            (3)监听的状态

    3. Runloop运行逻辑
    
    4.Runloop应用
        1)NSTimer
        2)ImageView显示:控制方法在特定的模式下可用
        3)PerformSelector
        4)常驻线程:在子线程中开启一个runloop
        5)自动释放池
            第一次创建:进入runloop的时候
            最后一次释放:runloop退出的时候
            其它创建和释放:当runloop即将休眠的时候会把之前的自动释放池释放,然后重新创建一个新的释放池

Runloop运行原理图
Runloop和相关类之间的关系图
Runloop运行逻辑
Runloop运行逻辑 2

相关文章

  • NSRunLoop作用

    NSRunLoop是IOS消息机制的处理模式 NSRunLoop的主要作用:控制NSRunLoop里面线程的执行和...

  • NSRunLoop

    NSRunLoop--NSRunLoop是IOS消息机制的处理模式,控制NSRunLoop里面线程的执行和休眠,在...

  • NSRunLoop 详解

    1.NSRunLoop是IOS消息机制的处理模式 NSRunLoop的主要作用:控制NSRunLoop里面线程的执...

  • NSRunLoop详解

    1.NSRunLoop是IOS消息机制的处理模式 NSRunLoop的主要作用:控制NSRunLoop里面线程的执...

  • 【转】NSRunLoop详解

    1.NSRunLoop是IOS消息机制的处理模式 NSRunLoop的主要作用:控制NSRunLoop里面线程的执...

  • iOS面试题06-应用程序(★★)

    《2018 iOS面试题系列》 一、NSRunLoop的实现机制,及在多线程中如何使用 NSRunLoop是IOS...

  • runloop

    NSRunLoop:OSX/iOS 系统中,提供了两个这样的对象:NSRunLoop 和 CFRunLoopRef...

  • 实现定时器功能的几种方式

    nsrunLoopGCDRAC NsrunLoop NSRunLoop是IOS消息机制的处理模式 一条线程对应一个...

  • NSRunLoop的使用

    版本:iOS13.6 本文仅介绍api的作用若想了解NSRunloop,可点击NSRunloop 简单细说。若想了...

  • NSTimer

    深入NSTimer(iOS)iOS 中的 NSTimer关于NSRunLoop和NSTimer的深入理解

网友评论

      本文标题:iOS NSRunLoop

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