iOS开发笔记--Run Loops(简洁版)

来源:互联网 发布:点位图软件 brd 编辑:程序博客网 时间:2024/04/30 16:28



2012-09-17 11:29 451人阅读 评论(1)收藏 举报

 分类:

iOS开发笔记(2) 

版权声明:本文为博主原创文章,未经博主允许不得转载。


一、概念


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创建。


创建观察者的代码示例

[plain] view plaincopy


  1. - (void)main  
  2. {  
  3.      NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];  
  4.      
  5.     //get runloop object  
  6.     NSRunLoop*runLoop = [NSRunLoop currentRunLoop];  
  7.      
  8.     //create arun loop observer and attach it to the run loop  
  9.    CFRunLoopObserverContext context = {0,self,NULL,NULL,NULL};  
  10.    CFRunLoopObserverRef runLoopObserver =CFRunLoopObserverCreate(kCFAllocatorDefault,kCFRunLoopBeforeSources, YES, 0,&runLoopObserverCallBack,&context);  
  11.     if(runLoopObserver)  
  12.     {  
  13.        CFRunLoopRefrunLoopRef = [runLoop getCFRunLoop];  
  14.       CFRunLoopAddObserver(runLoopRef, runLoopObserver,kCFRunLoopDefaultMode);  
  15.     }  
  16.         
  17.     while(!self.isCancelled && [runLooprunMode:NSDefaultRunLoopMode beforeDate:[NSDatedistantFuture]]);  
  18.      
  19.     [pool drain];  
  20. }  




3.启动run loop

有几种方法启动run loop,包括以下几种:

  • 无条件的
  • 预设时间
  • 特定模式

无条件的进入run loop是最简单的选择,但是不推荐。无条件运行run loop使线程进入固定的循环,你对runloop只有很少的控制。可以添加或移除事件来源,停止run loop的唯一方式是杀死线程。并且也不能在定制的模式下运行。


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


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


示例代码

[plain] view plaincopy


  1.    
  2. - (void)main  
  3. {  
  4.    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];  
  5.      
  6.     //get runloop object  
  7.     NSRunLoop*runLoop = [NSRunLoop currentRunLoop];  
  8.      
  9.     //create arun loop observer and attach it to the run loop  
  10.    CFRunLoopObserverContext context = {0,self,NULL,NULL,NULL};  
  11.    CFRunLoopObserverRef runLoopObserver =CFRunLoopObserverCreate(kCFAllocatorDefault,kCFRunLoopBeforeSources, YES, 0,&runLoopObserverCallBack,&context);  
  12.     if(runLoopObserver)  
  13.     {  
  14.        CFRunLoopRefrunLoopRef = [runLoop getCFRunLoop];  
  15.       CFRunLoopAddObserver(runLoopRef, runLoopObserver,kCFRunLoopDefaultMode);  
  16.     }  
  17.      
  18.     BOOL done =NO;  
  19.      
  20.     do {  
  21.        //start runloop but return after each source is handled  
  22.        SInt32result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 10, YES);  
  23.         
  24.        // If asource explicitly stopped the run loop, or if there are no  
  25.        // sources or timers, go ahead and exit.  
  26.        if (result== kCFRunLoopRunStopped || result == kCFRunLoopRunStopped)  
  27.        {  
  28.           done =YES;  
  29.        }  
  30.     } while(!done);  
  31.         
  32. //    while(!self.isCancelled && [runLooprunMode:NSDefaultRunLoopMode beforeDate:[NSDatedistantFuture]]);  
  33.      
  34.     [pool drain];  
  35. }  




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源

暂时搁置,有需要再研读。


http://blog.csdn.net/albert_zhao/article/details/7986865

0 0
原创粉丝点击