美文网首页
runloop笔记

runloop笔记

作者: TAsama | 来源:发表于2018-12-15 10:39 被阅读0次

    runloop运行循环

    目的:
    1. 保证程序不退出
    2. 负责监听所有事件
      硬件-->操作系统-->应用程序-->runloop(事件传递流程)
      runloop每做完一件事就进入睡眠
    3. RunLoop在一次循环中渲染UI

    runloop的运行模式

    1. DefaultRunLoopMode (只要有事件,就处理)
    2. UITrackingRunloopMode (只有当有UI事件交互发生时,runloop才会切换到,并且该模式会优先切换)
    3. NSRunLoopCommonModes (这并非一种模式,仅仅只是一种占位符,表示同时处在Default和UITracking两种模式下)
    runloop处理三件事:
    1. Source:源,输入源
    2. Observer:观察者,观察runloop
    3. Timer:定时器

    RunLoop与多线程的关系

    当定时器在子线程中运行时,子线程在任务运行结束后会被回收,因此定时器也无法执行。
    为什么子线程会被回收呢?因为子线程中的runloop默认是不会开启循环的。
    为了让子线程不会被回收,我们要开启子线程的runloop

    [[NSRunLoop currentRunLoop] run]; //这是一个死循环
    

    因此我们可以在子线程中进行耗时操作,同时开启子线程中的runLoop,使子线程保持,同时又不会影响主线程。
    但是,使用上面的方式开启了runloop后也会产生问题,runLoop不会结束了。我们并不想要这种结果。于是产生了下面的方式

    while(_finished) {
        [NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceReferenceDate:0.01f]];
    }
    

    这样一来我们可以通过控制finished这个参数来控制runLoop的保持

    GCD与RunLoop的关系

    看如下代码实例:

    @interface ViewController ()
    // 声明一个dispatch_source_t对象
    @property (nonatomic, strong) dispatch_source_t timer;
    
    @end
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
        self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
        
        dispatch_time_t start_time = DISPATCH_TIME_NOW;
        dispatch_time_t interval = 1.0 * NSEC_PER_SEC;
        // 定时器对象,启动时间,持续时间(纳秒),等待时间
        dispatch_source_set_timer(self.timer, start_time, interval, 0);
        
        //事件
        dispatch_source_set_event_handler(self.timer, ^{
            NSLog(@"----------------------%@", [NSThread currentThread]);
        });
        dispatch_resume(self.timer);
    }
    

    定时器全局队列中执行,即子线程中运行,此时,子线程中的runloop就已经被启动了。

    处理UI线程的耗时操作

    当我们在主线程加载大量图片的时候,主线程会发生卡顿。
    原因在与,系统会在一次runloop中渲染UI,除了一次性加载大量内存造成的卡顿外,一次性渲染UI也会造成一定程度的卡顿现象。下面的例子里,我们可以利用RunLoop的监听回调,在runLoop中自定义执行任务。

    static void callback(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) {
        
        NSLog(@"%@", info);
    }
    
    - (void)addObserver {
        
        CFRunLoopRef runLoop = CFRunLoopGetMain();
        CFRunLoopObserverRef defaultObserver;
        
        CFRunLoopObserverContext context = {
            
            0,
            (__bridge void *)(self),
            &CFRetain,
            &CFRelease,
            NULL
        };
        defaultObserver = CFRunLoopObserverCreate(NULL, kCFRunLoopAfterWaiting, YES, 0, &callback, &context);
        CFRunLoopAddObserver(runLoop, defaultObserver, kCFRunLoopCommonModes);
        CFRelease(defaultObserver);
    }
    

    kCFRunLoopAfterWaiting是观察模式,规定当RunLoop被唤醒后,执行回调。所以我们可以用各种方式(比如定时器)来唤醒runloop,每唤醒一次runloop,就执行一次回调,保证每次回调在一个独立的runloop内执行,以此来分散耗时操作。

    相关文章

      网友评论

          本文标题:runloop笔记

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