RunLoop

作者: weyan | 来源:发表于2018-11-26 08:30 被阅读0次

    1、 Runloop

    RunLoop RunLoop RunLoop RunLoop RunLoop对象 RunLoop资料 运行结构(RunLoop处理逻辑-官方版) RunLoop处理逻辑

    2、RunLoop与线程

    RunLoop与线程
    #import "ViewController.h"
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
    {
        //OC语言的API
        //01 获得主线程对应的runloop对象 主运行循环
        NSRunLoop *mainRunloop = [NSRunLoop mainRunLoop];
        //NSLog(@"%@",mainRunloop);
        
        //02 获得当前的runloop对象
        NSRunLoop *currentRunloop = [NSRunLoop currentRunLoop];
    //    NSLog(@"%p---%p",currentRunloop,mainRunloop);
        
        
        //C语言的API
        //01 主运行循环
        CFRunLoopRef mainRunloopRef = CFRunLoopGetMain();
        //02 当前的运行循环
        CFRunLoopRef currentRunloopRef = CFRunLoopGetCurrent();
        NSLog(@"%p-%p",mainRunloopRef,currentRunloopRef);
        
        //转换
        NSLog(@"%p-%p",mainRunloop.getCFRunLoop,mainRunloopRef);
        
        [NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];
    }
    
    -(void)run{
        NSLog(@"run---%@",[NSThread currentThread]);
        //子线程调用
        //NSLog(@"%@",[NSRunLoop currentRunLoop]);
        
        //runloop和线程的关系
        //(1) 一一的对应的关系(字典)
        //(2) 主线程对应的runloop默认已经创建并且开启了,而子线程对应的runloop需要手动创建并开启
        //(3) 线程销毁,那么runloop也将销毁
        
        //获得子线程对应的runloop |currentRunLoop该方法本身是懒加载的,如果是第一调用那么会创建当前线程对应的runloop并保存,以后调用则直接获取
        NSRunLoop *newThreadRunloop = [NSRunLoop currentRunLoop];
        NSLog(@"%@",newThreadRunloop);
        
        [newThreadRunloop run]; //开启runloop (该runloop开启后马上退出了)
    }
    
    @end
    

    3、RunLoop相关类

    RunLoop相关类 RunLoop运行模式 RunLoop运行模式 几种运行模式
    ----------------------RunLoop运行模式和Timer------------------------
    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
    {
        [self performSelectorInBackground:@selector(timer2) withObject:nil];
    }
    
    -(void)timer1
    {
        //01 创建定时器对象
        NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
        
        //02 添加到runloop中
        //Mode :runloop的运行模式(5-默认|界面跟踪|占位)
        //把定时器对象添加到runloop中,并指定运行模式为默认:(只有当运行模式为NSDefaultRunLoopMode的时候,定时器才会工作)
        //[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
        
        //当滚动textView的时候,主运行循环会切换运行模式(默认->界面追踪运行模式)
        //把定时器对象添加到runloop中,并指定运行模式为界面跟踪:(只有当运行模式为NUITrackingRunLoopMode的时候,定时器才会工作)
        //[[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];
        
        //要求不管有没有在滚动控件,定时器都能够正常工作
        //[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
        //[[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];
        
        //把定时器对象添加到runloop中,并指定运行模式为commonModes:
        //只有当运行模式为被标记为commonModes的运行模式的时候,定时器才会工作
        //被标记为commonModes运行模式:UITrackingRunLoopMode | kCFRunLoopDefaultMode
        /*
        common modes = <CFBasicHash 0x7fa4c9d00d70 [0x10a3f17b0]>{type = mutable set, count = 2,
            entries =>
            0 : <CFString 0x10b2ed270 [0x10a3f17b0]>{contents = "UITrackingRunLoopMode"}
            2 : <CFString 0x10a411b60 [0x10a3f17b0]>{contents = "kCFRunLoopDefaultMode"}
        }*/
        [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
    }
    
    -(void)timer2
    {
        NSLog(@"timer++++++%@",[NSThread currentThread]);
        
        //定时器工作
        //该方法内部会自动将创建的定时器对象添加到当前的runloop,并且指定运行模式为默认
        NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
        
        //为了保证滑动textView时,定时器继续工作,需要知道运行模式为占位模式
        [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
    
        //手动创建子线程对应的runloop
        [[NSRunLoop currentRunLoop] run];
    }
    
    -(void)run
    {
        NSLog(@"run----%@",[NSRunLoop currentRunLoop].currentMode);
    }
    

    4、GCD中的定时器

    #import "ViewController.h"
    
    @interface ViewController ()
    
    @property (nonatomic, strong) dispatch_source_t timer;
    
    
    @end
    
    @implementation ViewController
    
    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
    {
        //NSTimer中的定时器工作会受到runloop运行模式的影响
        //GCD中的定时器是精准的,不受影响
        
        //01 创建定时器对象
        /* 参数说明
         *
         * 第一个参数:source的类型 DISPATCH_SOURCE_TYPE_TIMER 定时器leixing
         * 第二个参数:对第一个参数的描述
         * 第三个参数:更详细的描述
         * 第四个参数:队列(GCD-4) 决定代码块(event_handler)在哪个线程中执行(串行队列-主线程|并发主队列-子线程)
         */
        dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
        
        //02 设置定时器(开始时间|调用间隔|精准度)
        /* 参数说明
         *
         * 第一个参数:定时器对象
         * 第二个参数:开始计时的时间  DISPATCH_TIME_NOW 现在开始
         * 第三个参数:间隔时间
         * 第四个参数:精准度(允许的误差)
         */
        dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 2.0 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
        
        //03 事件回调(定时器执行的任务)
        dispatch_source_set_event_handler(timer, ^{
            NSLog(@"GCD---%@",[NSThread currentThread]);
        });
        
        //04 启动定时器
        dispatch_resume(timer);
        
        //05 添加一个引用
        self.timer = timer;
    }
    @end
    

    5、CFRunLoopSourceRef

    CFRunLoopSourceRef就是inputSource 函数调用栈

    总结:

    RunLoop总结

    注意:
    1、有线程不一定有RunLoop,但有RunLoop就必须有线程
    2、线程销毁或者给runloop设定的时间到的话runloop就会退出

    6、CFRunLoopObserverRef

    CFRunLoopObserverRef
    -------------------------RunLoopObserverRef的使用------------------------
    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
    {
        /**01 创建观察者对象
        *参数说明:
        *allocator 分配存储空间(默认)
        *activities 需要监听runloop的状态
        *repeats 是否持续监听 yes
        *order   0
        */
        /**CFRunLoopObserverRef ob = CFRunLoopObserverCreateWithHandler(CFAllocatorRef allocator, CFOptionFlags activities, Boolean repeats, CFIndex order, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
         
        })
        */
        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(@"即将处理timer事件");
                    break;
                case kCFRunLoopBeforeSources:
                    NSLog(@"即将处理source事件");
                    break;
                case kCFRunLoopBeforeWaiting:
                    NSLog(@"即将进入休眠");
                    break;
                case kCFRunLoopAfterWaiting:
                    NSLog(@"被唤醒");
                    break;
                case kCFRunLoopExit:
                    NSLog(@"runloop退出");
                    break;
    
                default:
                    break;
            }
        });
    
      /*02 监听当前runloop的运行状态
       *参数说明
       *
       *第一参数:runloop对象
       *第二参数:监听者
       *第三参数:监听runloop在哪种运行模式下的状态
       */
        CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);
    
        [NSTimer scheduledTimerWithTimeInterval:4.0 target:self selector:@selector(timerRun) userInfo:nil repeats:YES];
    }
    
    -(void)timerRun
    {
        NSLog(@"处理收到的事件--timer--RUN");
    }
    

    7、代码模拟RunLoop死循环

    #import <Foundation/Foundation.h>
    
    void msg(int n){
        NSLog(@"runloop被唤醒");
        NSLog(@"runloop处理%d这个任务",n);
    }
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            NSLog(@"runloop启动啦");
            do {
                NSLog(@"runloop即将处理timer事件");
                 NSLog(@"runloop即将处理source事件");
                 NSLog(@"还有事件响应我来处理吗?");
                 NSLog(@"runloop进入到休眠");
                int number = 0;
                scanf("%d",&number);
                msg(number);
            } while (1);
        }
        return 0;
    }
    
    

    8、RunLoop的应用

    runloop应用
    • 应用01
    应用01
    • 应用02
    应用02

    9、关于RunLoop内部的自动释放池

    关于RunLoop内部的自动释放池

    相关文章

      网友评论

          本文标题:RunLoop

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