iOS开发笔记--Run Loops


一、概念

Run loops 是与线程相关的基础构造部分。
一个 run loop就是一个事件处理循环,调配任务和处理输入事件。
run loop的目标就是,有任务的时候保持忙碌,没有任务时休眠。

Cocoa和Core Foundation都提供run loop对象帮助我们配置和管理run loop。
应用不需要显示的创建run loop对象;每个线程,包括主线程都有与之相关的run loop对象。
主线程在程序启动后,会自行创建run loop对象,并运行;只有次线程需要显示的创建run loop对象,并运行。

1.事件来源
run loop有两种事件来源:输入源和定时源。
输入源传递异步消息,消息通常来自其他线程或者不同应用。
定时源传递同步消息,在安排的时间或重复的时间间隔发生。
两种源都使用应用特定的处理路径处理事件。

1)输入源
当你创建输入源后,需要把它分配给一种run loop模式
run loop模式影响在给定时刻哪种输入源会被监控。

输入源的种类
基于端口的源,可定制输入源,cocoa执行函数输入源。

基于端口的源 监控应用相关的端口。
可定制输入源 监控定制的事件来源。
cocoa执行函数输入源 cocoa定义了一个定制的输入源,允许你在任何线程执行函数选择器

2)定时源

2.run loop模式
run loop模式是一个集合,这个集合包括需要监控的输入源和定时源以及需要通知的run loop观察者。
每当你运行run loop时,要给它配一种模式。只有与这种模式相关的事件来源会被监控,并允许发送消息;只有与这种模式相关的runloop观察者会被通知。其他模式相关的事件来源会只有在其模式配给run loop时,才会起作用,否则暂停。

3.run loop观察者
可以创建以下事件相关的观察者
run loop入口
run loop将要处理定时源时
run loop将要处理输入源时
run loop将要休眠时
run loop已被唤醒, 且在它处理唤醒它的事件之前
run loop终止

二、何时使用run loop
只有创建次线程时,才需要显示地运行run loop。
没有必要在所有的情况下启动线程的run loop。例如,用线程执行某个长时间运行并且已经约定好的任务,就应该避免启动runloop。
你需要频繁或者更多地与线程交互,就需要使用run loop。
例如,在以下情况需要启动run loop:
使用端口源或者可定制的输入源与其他线程通信
使用定时器
在cocoa应用中使用 类似performSelector的方法
使用线程执行周期性任务

三、使用run loop对象
run loop对象提供主要的接口,向run loop添加输入源,定时器,观察者以及运行run loop。
每个线程都有一个关联的,单独的run loop对象。
在cocoa中,这个关联对象是NSRunLoop对象;在Carbon或BSD应用中,是CFRunLoopRef类型的指针。

1.获取run loop对象
1)
    NSRunLoop*runLoop = [NSRunLoop currentRunLoop];
    CFRunLoopRefrunLoopRef = [runLoop getCFRunLoop];
2)
    CFRunLoopRefrunLoopRef = CFRunLoopGetCurrent();

2.配置run loop
在次线程上运行run loop之前,必须至少添加一个输入源或者定时器。
如果run loop没有任何来源监控,当你试着运行它时就会立刻退出。
run loop观察者必须用Core Foundation创建。

创建观察者的代码示例
- (void)main
{
     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   
    //get runloop object
    NSRunLoop*runLoop = [NSRunLoop currentRunLoop];
   
    //create arun loop observer and attach it to the run loop
   CFRunLoopObserverContext context = {0,self,NULL,NULL,NULL};
   CFRunLoopObserverRef runLoopObserver =CFRunLoopObserverCreate(kCFAllocatorDefault,kCFRunLoopBeforeSources, YES, 0,&runLoopObserverCallBack,&context);
    if(runLoopObserver)
    {
       CFRunLoopRefrunLoopRef = [runLoop getCFRunLoop];
      CFRunLoopAddObserver(runLoopRef, runLoopObserver,kCFRunLoopDefaultMode);
    }
      
    while(!self.isCancelled && [runLooprunMode:NSDefaultRunLoopMode beforeDate:[NSDatedistantFuture]]);
   
    [pool drain];
}



3.启动run loop
有几种方法启动run loop,包括以下几种:
  • 无条件的
  • 预设时间
  • 特定模式
无条件的进入run loop是最简单的选择,但是不推荐。无条件运行run loop使线程进入固定的循环,你对runloop只有很少的控制。可以添加或移除事件来源,停止run loop的唯一方式是杀死线程。并且也不能在定制的模式下运行。

预设时间是一种更好的选择。runloop运行,知道接收到一个事件或者预设的时间过期。如果是接到事件,就把时间交给处理器处理,然后退出runloop,你可以重新启动run loop来处理下一个事件;如果是分派的时间过期,你可以简单地重启runloop,使用时间去做其他任何事情。

特定模式也是一种好的选择。模式与预设时间并不冲突,可以同时使用。

示例代码
 
- (void)main
{
   NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   
    //get runloop object
    NSRunLoop*runLoop = [NSRunLoop currentRunLoop];
   
    //create arun loop observer and attach it to the run loop
   CFRunLoopObserverContext context = {0,self,NULL,NULL,NULL};
   CFRunLoopObserverRef runLoopObserver =CFRunLoopObserverCreate(kCFAllocatorDefault,kCFRunLoopBeforeSources, YES, 0,&runLoopObserverCallBack,&context);
    if(runLoopObserver)
    {
       CFRunLoopRefrunLoopRef = [runLoop getCFRunLoop];
      CFRunLoopAddObserver(runLoopRef, runLoopObserver,kCFRunLoopDefaultMode);
    }
   
    BOOL done =NO;
   
    do {
       //start runloop but return after each source is handled
       SInt32result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 10, YES);
      
       // If asource explicitly stopped the run loop, or if there are no
       // sources or timers, go ahead and exit.
       if (result== kCFRunLoopRunStopped || result == kCFRunLoopRunStopped)
       {
          done =YES;
       }
    } while(!done);
      
//    while(!self.isCancelled && [runLooprunMode:NSDefaultRunLoopMode beforeDate:[NSDatedistantFuture]]);
   
    [pool drain];
}



4.退出run loop
有两种方法:
  • 设定一个时限运行run loop
  • 停止 run loop
如果可以设置的话,设定时限的方法优先选择。这种方法可以使runloop在退出之前,完成所有正常的操作,包括发送通知给所有观察者。
使用CFRunLoopStop方法退出run loop,效果与设定时限类似。区别是无条件启动run loop时,不可以使用。

5.线程安全与run loop对象
Core Foundation的方法都是线程安全的。可以在任何线程调用。如果在配置过的run loop执行操作,最好是在拥有该runloop的线程中操作。

NSRunLoop是线程不安全的。使用NSRunLoop配置run loop时,最好在该runloop所属的线程中操作,否则结果不可预期或者崩溃。

四、配置run loop源
暂时搁置,有需要再研读。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值