一、Runloop简介: 
Run loops 是线程相关的的基础框架的一部分。一个 run loop 就是一个事件处理 的循环,用来不停的调度工作以及处理输入事件。 
使用 run loop的目的是让你的线程在有工作的时候忙于工作,而没工作的时候处于休眠状态。 
Runloop还可以在loop在循环中的同时响应其他输入源,比如界面控件的按钮,手势等。 
  
Run loop 接收输入事件来自两种不同的来源: 
输入源(input source)和定时源 (timer source)。 
输入源传递异步事件,通常消息来自于其他线程或程序。输入源的种类:基于端口的输入源和自定义输入源。 
定时源则传递同步事件,发生在特定时间或者重复的时间间隔。 
  
Run loop 模式是所有要监视的输入源和定时源以及要通知的 run loop 注册观察 者的集合。 
可以将 Run loop 观察者和以下事件关联: 
Run loop 入口 
Run loop 何时处理一个定时器 
Run loop 何时处理一个输入源 
Run loop 何时进入睡眠状态 
Run loop 何时被唤醒,但在唤醒之前要处理的事件 
Run loop 终止 
  
每次运行 Run loop,你线程的 Run loop 对会自动处理之前未处理的消息,并通知相关的观察者。具体的顺序如下: 
1. 通知观察者 Run loop 已经启动。 
2. 通知观察者任何即将要开始的定时器。 
3. 通知观察者任何即将启动的非基于端口的源。 
4. 启动任何准备好的非基于端口的源。 
5. 如果基于端口的源准备好并处于等待状态,立即启动;并进入步骤 9。 
6. 通知观察者线程进入休眠。 
7. 将线程置于休眠直到任一下面的事件发生: 
   某一事件到达基于端口的源; 
   定时器启动; 
   Run loop 设置的时间已经超时; 
   Run loop 被显式唤醒。 
8. 通知观察者线程将被唤醒。 
9. 处理未处理的事件 
   如果用户定义的定时器启动,处理定时器事件并重启 Run loop。进入步骤 2。 
   如果输入源启动,传递相应的消息。 
   如果 Run loop 被显式唤醒而且时间还没超时,重启 Run loop,进入步骤 2。 
10. 通知观察者 Run loop 结束。 
  
Run loop 在你要和线程有更多的交互时才需要,比如以下情况: 
使用端口或自定义输入源来和其他线程通信; 
使用线程的定时器; 
Cocoa 中使用任何performSelector...的方法; 
使线程周期性工作。 
  
二、举例说明Runloop的优点。 
一般情况下,当我们使用NSRunLoop的时候,代码如下所示: 
do { 
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopModebeforeDate:[NSDate distantFuture]]; 
} while (!done); 
在上面的代码中,参数done为NO的时候,当前runloop会一直接收处理其他输入源,处理输入源之后会再回到runloop中等待其他的输入源;除非done为NO,否则当前流程一直再runloop中。 
如下面的代码片段所示,有三个按钮,分别对应如下三个action消息,buttonNormalThreadTestPressed,buttonRunloopPressed,buttonTestPressed。 
buttonNormalThreadTestPressed:启动一个线程,在while循环中等待线程执行完再接着往下运行。 
buttonRunloopPressed:启动一个线程,使用runloop,等待线程执行完再接着往下运行。 
buttonTestPressed:仅仅打印两条日志,用来测试UI是否能立即响应的。 
在本测试中,待程序运行后,做如下操作对比: 
1、点击buttonNormalThreadTestPressed,然后立刻点击buttonTestPressed,查看日志输出。 
2、待1完成后,点击buttonRunloopPressed,然后立刻点击buttonTestPressed,查看日志输出,跟1的日志做对比,即可以发现步骤2即使线程没有完成,在runloop等待过程中,界面仍然能够响应。 
  
BOOL threadProcess1Finished =NO; 
-(void)threadProce1{ 
    NSLog(@"Enter threadProce1."); 
    
    for (int i=0; i<5;i++) { 
        NSLog(@"InthreadProce1 count = %d.", i); 
        sleep(1); 
    }    
    threadProcess1Finished =YES;     
    NSLog(@"Exit threadProce1."); 
} 
  
BOOL threadProcess2Finished =NO; 
-(void)threadProce2{ 
    NSLog(@"Enter threadProce2."); 
    
    for (int i=0; i<5;i++) { 
        NSLog(@"InthreadProce2 count = %d.", i); 
        sleep(1); 
    } 
    
    threadProcess2Finished =YES;    
    NSLog(@"Exit threadProce2."); 
} 
  
- (IBAction)buttonNormalThreadTestPressed:(UIButton *)sender { 
    NSLog(@"EnterbuttonNormalThreadTestPressed"); 
    
    threadProcess1Finished =NO; 
    NSLog(@"Start a new thread."); 
    [NSThreaddetachNewThreadSelector: @selector(threadProce1) 
                             toTarget: self 
                           withObject: nil]; 
    
    // 通常等待线程处理完后再继续操作的代码如下面的形式。 
    // 在等待线程threadProce1结束之前,调用buttonTestPressed,界面没有响应,直到threadProce1运行完,才打印buttonTestPressed里面的日志。 
    while (!threadProcess1Finished) { 
        [NSThreadsleepForTimeInterval: 0.5]; 
    } 
    
    NSLog(@"ExitbuttonNormalThreadTestPressed");    
} 
  
- (IBAction)buttonRunloopPressed:(id)sender { 
    NSLog(@"Enter buttonRunloopPressed"); 
    threadProcess2Finished =NO; 
    NSLog(@"Start a new thread."); 
    [NSThreaddetachNewThreadSelector: @selector(threadProce2) 
                             toTarget: self 
                           withObject: nil]; 
 |   
        
 
    
    
    
     
 
 |