zoukankan      html  css  js  c++  java
  • 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
    标签: iOSRUNLOOP
  • 相关阅读:
    python 基础2.5 循环中continue与breake用法
    python 基础 2.4 while 循环
    python 基础 2.3 for 循环
    python 基础 2.2 if流程控制(二)
    python 基础 2.1 if 流程控制(一)
    python 基础 1.6 python 帮助信息及数据类型间相互转换
    python 基础 1.5 python数据类型(四)--字典常用方法示例
    Tornado Web 框架
    LinkCode 第k个排列
    LeetCode 46. Permutations
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2848129.html
Copyright © 2011-2022 走看看