zoukankan      html  css  js  c++  java
  • iOS开发RunLoop学习:一:RunLoop简单介绍

    一:RunLoop的简单介绍

    #import "ViewController.h"
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    /**
     *  1:Runloop和线程的关系:1:一一对应,主线程的runloop已经默认创建,但是子线程的需要手动创建:创建子线程的runloop: NSRunLoop *run = [NSRunLoop currentRunLoop];currentRunLoop懒加载的,在同一个子线程中创建多个runloop,则返回的都是同一个对象,因为其是懒加载模式的 2:在runloop中有多个运行模式,但是runloop只能选择一种模式运行,mode里面至少要有一个timer或者是source
        2:1.获得主线程对应的runloop:NSRunLoop *mainRunLoop = [NSRunLoop mainRunLoop]; 2:获得当前线程对应的runLoop:NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop];
        3:CFRunLoop:1:获得主线程对应的runloop:CFRunLoopGetMain() 2:获得当前线程对应的runLoop:CFRunLoopGetCurrent()
     *
     */
    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
    {
        //1.获得主线程对应的runloop
        NSRunLoop *mainRunLoop = [NSRunLoop mainRunLoop];
        
        //2.获得当前线程对应的runLoop
        NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop];
        
        NSLog(@"%p---%p",mainRunLoop,currentRunLoop);
    //    NSLog(@"%@",mainRunLoop);
        
        //Core
        NSLog(@"%p",CFRunLoopGetMain());
        NSLog(@"%p",CFRunLoopGetCurrent());
        
        NSLog(@"%p",mainRunLoop.getCFRunLoop);
        
        //Runloop和线程的关系
        //一一对应,主线程的runloop已经创建,但是子线程的需要手动创建
        [[[NSThread alloc]initWithTarget:self selector:@selector(run) object:nil] start];
    }
    
    //在runloop中有多个运行模式,但是runloop只能选择一种模式运行
    //mode里面至少要有一个timer或者是source
    -(void)run
    {
        //如何创建子线程对应的runLoop,currentRunLoop懒加载的
        NSLog(@"%@",[NSRunLoop currentRunLoop]);
        NSLog(@"%@",[NSRunLoop currentRunLoop]);
        NSLog(@"run---%@",[NSThread currentThread]);
    }
    
    @end

     

     

    #import "ViewController.h"
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    /**
     * 1:NSLog(@"%@",[NSRunLoop currentRunLoop]);打印当前线程的RunLoop,懒加载模式,一条线程对应一个RunLoop对象,有返回,没有创建,主线程的RunLoop默认创建,子线程的RunLoop需要手动创建,[NSRunLoop currentRunLoop],同一个线程中若是创建多个RunLoop,则返回的都是同一个RunLoop对象,一个RunLoop里会有多个mode运行模式(系统提供了5个),但运行时只能指定一个RunLoop,若是切换RunLoop,则需要退出当前的RunLoop
     2:定时器NSTimer问题:1:若是创建定时器用timerWithTimeInterval,则需要手动将定时器添加到NSRunLoop中,指定的运行模式为default,但是如果有滚动事件的时候,定时器就会停止工作。解决办法:更改NSRunLoop的运行模式,UITrackingRunLoopMode界面追踪,此模式是当只有发生滚动事件的时候才会开启定时器。若是任何时候都会开启定时器: NSRunLoopCommonModes, 
       NSRunLoopCommonModes = NSDefaultRunLoopMode + UITrackingRunLoopMode
      占用,标签,凡是添加到NSRunLoopCommonModes中的事件爱你都会被同时添加到打上commmon标签的运行模式上
     
     3:1:scheduledTimerWithTimeInterval此方法创建的定时器默认加到了NSRunLoop中,并且设置运行模式为默认。 2:若是想在子线程开启NSRunLoop:需要手动开启:NSRunLoop *currentRunloop = [NSRunLoop currentRunLoop];等到线程销毁的时候currentRunloop对象也随即销毁。2:在子线程的定时器,需要手动加入到runloop:不要忘记调用run方法
    
     NSRunLoop *currentRunloop = [NSRunLoop currentRunLoop];
     
     //该方法内部自动添加到runloop中,并且设置运行模式为默认
     [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
     
     //开启runloop
     [currentRunloop run];
     
     
     /*
     *
     */
    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
    {
    //    NSLog(@"%@",[NSRunLoop currentRunLoop]);
        
    //    [self timer2];
    //    [NSThread detachNewThreadSelector:@selector(timer2) toTarget:self withObject:nil];
        [self timer1];
    }
    
    -(void)timer1
    {
        //1.创建定时器
       NSTimer *timer =  [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
        
        //2.添加定时器到runLoop中,指定runloop的运行模式为NSDefaultRunLoopMode
        /*
         第一个参数:定时器
         第二个参数:runloop的运行模式
         */
    //    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
        
        //UITrackingRunLoopMode:界面追踪
       [[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];
    
    //    NSRunLoopCommonModes = NSDefaultRunLoopMode + UITrackingRunLoopMode
        //占用,标签,凡是添加到NSRunLoopCommonModes中的事件爱你都会被同时添加到打上commmon标签的运行模式上
        /*
         0 : <CFString 0x10af41270 [0x10a0457b0]>{contents = "UITrackingRunLoopMode"}
         2 : <CFString 0x10a065b60 [0x10a0457b0]>{contents = "kCFRunLoopDefaultMode"
         */
    //    [[NSRunLoop currentRunLoop]addTimer:timer forMode:NSRunLoopCommonModes];
    }
    
    -(void)timer2
    {
        NSRunLoop *currentRunloop = [NSRunLoop currentRunLoop];
        
        //该方法内部自动添加到runloop中,并且设置运行模式为默认
        [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
        
        //开启runloop
        [currentRunloop run];
    }
    
    -(void)run
    {
        NSLog(@"run-----%@---%@",[NSThread currentThread],[NSRunLoop currentRunLoop].currentMode);
    }
    
    @end

    ####1.Runloop基础知识

    - 1.1 字面意思

    a 运行循环

    b 跑圈

    - 1.2 基本作用(作用重大)

    a 保持程序的持续运行(ios程序为什么能一直活着不会死)

    b 处理app中的各种事件(比如触摸事件、定时器事件【NSTimer】、selector事件【选择器·performSelector···】)

    c 节省CPU资源,提高程序性能,有事情就做事情,没事情就休息

    - 1.3 重要说明

            (1)如果没有Runloop,那么程序一启动就会退出,什么事情都做不了。

            (2)如果有了Runloop,那么相当于在内部有一个死循环,能够保证程序的持续运行

            (2)main函数中的Runloop

            a 在UIApplication函数内部就启动了一个Runloop

            该函数返回一个int类型的值

            b 这个默认启动的Runloop是跟主线程相关联的

    - 1.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层面)

    - 1.5 Runloop参考资料

    ```objc

    (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/

    ```

    - 1.6 Runloop与线程

    1.Runloop和线程的关系:一个Runloop对应着一条唯一的线程

        问题:如何让子线程不死

        回答:给这条子线程开启一个Runloop

    2.Runloop的创建:主线程Runloop已经创建好了,子线程的runloop需要手动创建

    3.Runloop的生命周期:在第一次获取时创建,在线程结束时销毁

    - 1.7 获得Runloop对象

    ```objc

    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。

    ```

    - 1.8 Runloop相关类

    (1)Runloop运行原理图

    ![PNG](2.png)

    (2)五个相关的类

    a.CFRunloopRef

    b.CFRunloopModeRef【Runloop的运行模式】

    c.CFRunloopSourceRef【Runloop要处理的事件源】

    d.CFRunloopTimerRef【Timer事件】

    e.CFRunloopObserverRef【Runloop的观察者(监听者)】

    (3)Runloop和相关类之间的关系图

     ![PNG](1.png)

    (4)Runloop要想跑起来,它的内部必须要有一个mode,这个mode里面必须有sourceobserver imer,至少要有其中的一个。

    - CFRunloopModeRef

        1.CFRunloopModeRef代表着Runloop的运行模式

        2.一个Runloop中可以有多个mode,一个mode里面又可以有多个sourceobserver imer等等

        3.每次runloop启动的时候,只能指定一个mode,这个mode被称为该Runloop的当前mode

        4.如果需要切换mode,只能先退出当前Runloop,再重新指定一个mode进入

        5.这样做主要是为了分割不同组的定时器等,让他们相互之间不受影响

        6.系统默认注册了5个mode

            a.kCFRunLoopDefaultMode:App的默认Mode,通常主线程是在这个Mode下运行

                b.UITrackingRunLoopMode:界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响

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

                d.GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,通常用不到

                e.kCFRunLoopCommonModes: 这是一个占位用的Mode,不是一种真正的Mode

  • 相关阅读:
    快速排序学习
    转载 libSVM介绍(二)
    支持向量机: Maximum Margin Classifier
    联发科笔试题之字符编码
    研究1
    在OnLButtonDown获取其他控件被点击的消息
    希尔排序学习
    快速排序
    别人的string的实现,有时间好好学习下
    完成动态根据类别动态填充区域颜色
  • 原文地址:https://www.cnblogs.com/cqb-learner/p/5859431.html
Copyright © 2011-2022 走看看