美文网首页
Runloop 简介

Runloop 简介

作者: End_枫 | 来源:发表于2016-10-30 14:47 被阅读13次

Runloop 是 iOS 和 OSX 中和线程相关的基础概念。提供了线程循环处理事件的能力,当有事件处理时唤醒线程工作,空闲时使线程进入休眠,以合理的利用系统资源。

Runloop 是线程相关的概念,和线程是一一对应的。一个线程对应一个runloop,默认情况下,主线程的 runloop 是启动的,后台线程的 runloop 需要自己启动。

Runloop 的工作模型类似 windows 中的消息机制(Event loop),接受事件(消息)->处理->等待新事件(消息),伪代码如下:

loop()
{
    init();
    while(get_message(&msg) != quit){
        handle_message(msg);
    }
}

Runloop 中需要处理的事件分2类:

  1. 输入源(input source):分发异步事件,通常都是来自其他线程或者Application。
  • performSelector源
  • 基于端口的源(mach port)
  • 自定义输入源
  1. 计时器:定时的或者一定间隔的触发同步事件。

Runloop 的运行结构图如下图:


2015-08-23-ios-runloop.jpg

Runloop 其实是一个对象,提供了一个入口函数来执行上面的事件循环,在函数内部实现了接受消息->处理->等待新消息这样的一个循环流程,直到循环结束。

Runloop 运行中会发出许多通知,比如状态的改变,可以监听这些通知作对应的处理。
iOS 和 OSX 中提供了2个这样的对象:NSRunloop和CFRunLoopRef。

内部逻辑大致如下图:


2015-08-23-ios-runloop_1.png

运行模式

运行模式定义了一个集合,当 Runloop 运行在某个模式下时,只会监听某些类型的输入源事件和计时器事件,以及分发某些特定种类的通知,启动 Runloop 时会指定一种模式。

常见的一些运行模式:

  • NSDefaultRunLoopMode:默认模式,包括了大部分的操作事件,绝大部份情况下都应该使用这个模式配置自己的 runloop
  • NSEventTrackingRunLoopMode:典型的当 scrollView 滚动的时候是运行在该模式下,此时的不接受Timer事件,所以Timer会失效
  • NSRunLoopCommonModes:模式组,一个模式将自己标记为“common”属性后就会在该组中,运行在该模式下,能处理的事件就是组中各个模式能处理事件的合集,在默认情况下,NSDefaultRunLoopMode 和NSEventTrackingRunLoopMode 被标记为 “common” 属性

输入源

  • 基于端口的源:监听Mach port,cocoa 提供了内置的类来实现这类输入源 NSPort (IPC相关)
  • 自定义输入源:
  • PerformSelector源:主要是那些和时间能扯上关系的API,比如:(其实是通过timer实现的)
    • performSelectorOnMainThread:withObject:waitUntilDone:
    • performSelector:withObject:afterDelay:
    • performSelector:onThread:withObject:waitUntilDone:

Runloop 的使用

  • 使用端口或者自定义输入源来实现线程间的通信
  • 在线程中使用计时器
  • 使用performSelector方法
  • 保持线程执行周期性的任务

Runloop 的应用

  • Autorelease pool:runloop 会自动维护autorelease pool的创建和释放,autorelease pool 会在下一次runloop循环之前释放 pool 中的对象,所以在像for,while这样的循环中,如果需要大量创建临时对象时需要自己创建autorelease pool,避免临时内存峰值过高,比如图片相关的操作
  • 事件响应(触摸/锁屏/摇晃等):source1 事件
  • 手势识别:监听特定的通知,处理手势的回调
  • 界面更新:监听特定的通知,处理界面的刷新操作
  • 定时器:NSTimer 和 CADisplayLink
  • PerformSelector:AfterDelay:
  • GCD:dispatch_async(dispatch_get_main_queue(), block)

附 Runloop 的部分源码图:


屏幕快照 2016-01-28 上午10.33.57.png

一个使用 Runloop 的简单例子

- (void)threadMain 
{ 
    // The application uses garbage collection, so no autorelease pool is needed. 
    NSRunLoop* myRunLoop = [NSRunLoop currentRunLoop]; 
 
    // Create a run loop observer and attach it to the run loop. 
    CFRunLoopObserverContext  context = {0, self, NULL, NULL, NULL}; 
    CFRunLoopObserverRef    observer = CFRunLoopObserverCreate(kCFAllocatorDefault, 
            kCFRunLoopAllActivities, YES, 0, &myRunLoopObserver, &context); 
 
    if (observer) 
    { 
        CFRunLoopRef    cfLoop = [myRunLoop getCFRunLoop]; 
        CFRunLoopAddObserver(cfLoop, observer, kCFRunLoopDefaultMode); 
    } 
 
    // Create and schedule the timer. 
    [NSTimer scheduledTimerWithTimeInterval:0.1 target:self 
                selector:@selector(doFireTimer:) userInfo:nil repeats:YES]; 
 
    NSInteger    loopCount = 10; 
    do 
    { 
        // Run the run loop 10 times to let the timer fire. 
        [myRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]]; 
        loopCount--; 
    } 
    while (loopCount); 
}

案例

AFNetworking

相关文章

网友评论

      本文标题:Runloop 简介

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