好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

IOS NSRunLoop的一点理解

IOS NSRunLoop的一点理解

一、类定义

   + (NSRunLoop *)currentRunLoop
    如果调用的线程中没有runloop,那么将会创建一个并返回
  + (NSRunLoop *)mainRunLoop
    返回主线程的runloop

  - (void)acceptInputForMode:(NSString *)mode beforeDate:(NSDate *)limitDate
    运行loop一次或者直到limitDate。如果没有input sources加入到这个loop,那么马上返回;否则一直运行到limitDate,或者接口到一个input source然后返回。
  - (void)addPort:(NSPort *)aPort forMode:(NSString *)mode
  - (void)addTimer:(NSTimer *)aTimer forMode:(NSString *)mode
    port和timer都可以添加到多个mode中
  - (void)cancelPerformSelector:(SEL)aSelector target:(id)target argument:(id)anArgument
    取消所有mode中的perform select,argument必须跟指定调用时候的一样
  - (void)cancelPerformSelectorsWithTarget:(id)target
  - (NSString *)currentMode
    如果run loop没有运行,那么返回nil
  - (CFRunLoopRef)getCFRunLoop
  - (NSDate *)limitDateForMode:(NSString *)mode
    下一次运行的时间,如果没有指定的mode上没有input source,返回nil
  - (void)performSelector:(SEL)aSelector target:(id)target argument:(id)anArgument order:(NSUInteger)order modes:(NSArray *)modes
order值越低优先级越高
  - (void)removePort:(NSPort *)aPort forMode:(NSString *)mode
  - (void)run
    在default mode下无限运行loop,但是如果没有任何input source,会立即返回。手动移除所有已知的inout source并不能保证run loop停止运行,因为系统可能会添加一些input source。
  - (BOOL)runMode:(NSString *)mode beforeDate:(NSDate *)limitDate
    运行input source一次,为指定mode的input阻塞直到date的时间。如过没有input source,立即返回并返回NO。
  - (void)runUntilDate:(NSDate *)limitDate
  如果没有input source,立即返回。否则在limitDate到来之前,不停的循环。
再详细的就看文档吧

二、RunLoopMode
NSDefaultRunLoopMode  这是大多数操作中使用的模式。
NSConnectionReplyMode 该模式用来监控NSConnection对象。你通常不需要在你的代码中使用该模式。
NSModalPanelRunLoopMode Cocoa使用该模式来标识用于modal panel(模态面板)的事件。
NSEventTracking (UITrackingRunLoopMode) Cocoa使用该模式来处理用户界面相关的事件。
NSRunLoopCommonModes  这是一组可配置的通用模式。将input sources与该模式关联则同时也将input sources与该组中的其它模式进行了关联。对于Cocoa应用,该模式缺省的包含了default,modal以及event tracking模式。

  一个常见的问题就是,主线程中一个NSTimer添加在default mode中,当界面上有一些scroll view的滚动频繁发生导致run loop运行在UItraking mode中,从而这个timer没能如期望那般的运行。所以,我们就可以把这个timer加到 NSRunLoopCommonModes 中来解决(iOS中)。

三.疑团重重
来看看这张经典的图片


其中Input source是一些异步的事件,比如port,selector等,这个会让runUntilDate:跳出(当然指的是非主线程中的runloop)。Timer source是同步的,一个timer结束后,在重复时间后或者手动fire后才会再一次调用。

在来看看这张图片

它说明了用户对ui的操作实际上是一种port,会放到一个队列中传到loop,然后由loop交给主线程处理。loop就是一个循环,接受event,传递,继续。主线程是另一个循环,负责事件的处理与界面的显示。当然这两者关系复杂。

在看下面的代码

BOOL pageStillLoading =  YES;
 -( void )press:( id  )sender
{
    [(UIButton * )sender setSelected:YES];
    NSLog(  @"  begin  " );  //   1 
    [[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow: 10.0 ]];   //   2 
    NSLog( @"  end  " );  //   3 
 
    pageStillLoading  =  YES;
    [NSThread detachNewThreadSelector:@selector(loadPageInBackground:)toTarget:self withObject:nil];   //   4 
     while   (pageStillLoading) {
        [[NSRunLoop currentRunLoop] runMode:UITrackingRunLoopMode beforeDate:[NSDate distantFuture]];   //   5 
        NSLog( @"  while end  "  );
    }
    NSLog(  @"  over  "  );
    
}

 -( void )loadPageInBackground:( id  )sender
{
    sleep(  3 );  //   6 
    NSLog( @"  timer  " );  //   7 
    pageStillLoading = NO;  //   8 
}

我在viewcontroller的view上加了一个uibutton,并且事件是press。touch up inside,然后,不在碰触界面(A)。发生了什么?
看看log:

 2013 - 01 - 06   00 : 57 : 21.167  runloop[ 10146  :c07] begin
  2013 - 01 - 06   00 : 57 : 31.171  runloop[ 10146  :c07] end
  2013 - 01 - 06   00 : 57 : 34.173  runloop[ 10146 : 3703  ] timer
  2013 - 01 - 06   00 : 58 : 00.001  runloop[ 10146 :c07]  while   end
  2013 - 01 - 06   00 : 58 : 00.002  runloop[ 10146 :c07] over


pageStillLoading设置成NO之后过了近30s,while才结束。
如果我把5的mode改成NSRunLoopCommonModes或者在界面上在加一个按钮,然后不停的点击那个按钮(B),结果如下

 2013 - 01 - 06   01 : 01 : 23.944  runloop[ 10174  :c07] begin
                       2013-01-06 01            : 01 : 33.948  runloop[ 10174  :c07] end
  2013 - 01 - 06   01 : 01 : 34.023  runloop[ 10174 :c07]  while   end
.
.
.
  2013 - 01 - 06   01 : 01 : 36.943  runloop[ 10174 :c07]  while   end
  2013 - 01 - 06   01 : 01 : 36.950  runloop[ 10174  :370b] timer
  2013 - 01 - 06   01 : 01 : 37.016  runloop[ 10174 :c07]  while   end
  2013 - 01 - 06   01 : 01 : 37.016  runloop[ 10174 :c07] over

为什么?我们看下流程
当2执行的时候,主线程的事情就是运行runloop 10s,而这个runloop本来就在运行的,所以相当于主线程什么都不用做,空闲状态的主线程当然也可以继续响应界面上的ui事件哦。
当5执行的时候,也没有主线程什么事情,runMode:beforeDate:是要么接受到一个mode上的event,要么到date这个时间。所以,A中要等待很久,这句才会返回;而B中,却是不停的给他event,所以while语句执行了多次。

而且B说明,有非default mode的event一直往run loop中发消息。

 

 

分类:  iOS

标签:  iOS ,  RUNLOOP

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于IOS NSRunLoop的一点理解的详细内容...

  阅读:39次