RunLoop

作者: 阿凡提说AI | 来源:发表于2016-12-26 23:37 被阅读13次

    一、简介

    RunLoop的字面意思就是运行循环,跑圈。
    基本作用:

    • 保持程序的持续运行
    • 处理App中的各种事件(比如触摸事件、定时器事件、Selector事件)
    • 节省CPU资源,提高程序性能:该做事时做事,该休息时休息
    屏幕快照 2016-12-26 下午11.06.05.png
    第14行代码的UIApplicationMain函数内部就启动了一个RunLoop
    
    所以UIApplicationMain函数一直没有返回,保持了程序的持续运行
    
    这个默认启动的RunLoop是跟主线程相关联的
    

    二、RunLoop对象

    1.RunLoop对象
    iOS中有2套API来访问和使用RunLoop

    一种Foundation,NSRunLoop
    一种是CoreFoundation,CFRunLoopRef
    

    NSRunLoop和CFRunLoopRef都代表着RunLoop对象
    NSRunLoop是基于CFRunLoopRef的一层OC包装,所以要了解RunLoop内部结构,需要多研究CFRunLoopRef层面的API(Core Foundation层面)
    2.RunLoop与线程

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

    3.获得RunLoop对象

    • Foundation
    // 获得当前线程的RunLoop对象
    [NSRunLoop currentRunLoop];  
    // 获得主线程的RunLoop对象
    [NSRunLoop mainRunLoop];      
    
    • CoreFoundation
    // 获得当前线程的RunLoop对象
    CFRunLoopGetCurrent();
    
    // 获得主线程的RunLoop对象
    CFRunLoopGetMain();
    

    三、RunLoop相关类

    CoreFoundation中关于RunLoop的5个类

    CFRunLoopRef
    
    CFRunLoopModeRef
    
    CFRunLoopSourceRef
    
    CFRunLoopTimerRef
    
    CFRunLoopObserverRef
    

    1、CFRunLoopObserverRef是观察者,能够监听RunLoop的状态改变

    // 创建observer
        CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
            NSLog(@"----监听到RunLoop状态发生改变---%zd", activity);
        });
    
        // 添加观察者:监听RunLoop的状态
        CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);
        
        // 释放Observer
        CFRelease(observer);
    
    

    2.CFRunLoopTimerRef是基于时间的触发器,基本上说的就是NSTimer.
    3.CFRunLoopModeRef

    CFRunLoopModeRef代表RunLoop的运行模式
    一个 RunLoop包含若干个 Mode,每个Mode又包含若干个Source/Timer/Observer
    每次RunLoop启动时,只能指定其中一个 Mode,这个Mode被称作 CurrentMode
    如果需要切换Mode,只能退出Loop,再重新指定一个Mode进入
    这样做主要是为了分隔开不同组的Source/Timer/Observer,让其互不影响
    
    屏幕快照 2017-01-12 上午9.12.45.png

    4.CFRunLoopSourceRef是事件源(输入源)
    Source0:非基于Port的
    Source1:基于Port的

    - (void)viewDidLoad {
        [super viewDidLoad];
        
        self.thread = [[XMGThread alloc] initWithTarget:self selector:@selector(run) object:nil];
        [self.thread start];
    }
    
    
    - (void)run
    {
        NSLog(@"----------run----%@", [NSThread currentThread]);
        
        [[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
        [[NSRunLoop currentRunLoop] run];
        
        NSLog(@"---------");
    //    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
    //    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantFuture]];
    }
    
    
    

    四、RunLoop的处理逻辑

    007A4CE9-5050-4366-BA12-2F0D189DDEE4.png 6AF9977F-E0EC-4F9A-97E9-5B1B75375ADF.png

    五、GCD定时器

    #import "ViewController.h"
    
    @interface ViewController ()
    /** 定时器(这里不用带*,因为dispatch_source_t就是个类,内部已经包含了*) */
    @property (nonatomic, strong) dispatch_source_t timer;
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
    //    dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC));
    //    
    //    dispatch_after(when, dispatch_get_main_queue(), ^{
    //        NSLog(@"-------");
    //    });
    }
    
    int count = 0;
    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
        // 获得队列
    //    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
        dispatch_queue_t queue = dispatch_get_main_queue();
        
        // 创建一个定时器(dispatch_source_t本质还是个OC对象)
        self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
        
        // 设置定时器的各种属性(几时开始任务,每隔多长时间执行一次)
        // GCD的时间参数,一般是纳秒(1秒 == 10的9次方纳秒)
        // 何时开始执行第一个任务
        // dispatch_time(DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC) 比当前时间晚3秒
        dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC));
        uint64_t interval = (uint64_t)(1.0 * NSEC_PER_SEC);
        dispatch_source_set_timer(self.timer, start, interval, 0);
        
        // 设置回调
        dispatch_source_set_event_handler(self.timer, ^{
            NSLog(@"------------%@", [NSThread currentThread]);
            count++;
            
    //        if (count == 4) {
    //            // 取消定时器
    //            dispatch_cancel(self.timer);
    //            self.timer = nil;
    //        }
        });
        
        // 启动定时器
        dispatch_resume(self.timer);
    }
    @end
    
    

    相关文章

      网友评论

        本文标题:RunLoop

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