美文网首页
iOS 同步完成事件

iOS 同步完成事件

作者: 萧城x | 来源:发表于2017-03-19 20:57 被阅读120次

    经常我们会遇到一种情况 就是等待 队列的任务都完成的时候 才调用我们想要的运行的方式,希望整个过程是同步 不是异步的
    这里介绍一种实现

    弄清楚NSRunLoop确实需要花时间,这个类的概念和模式似乎是Apple的平台独有(iOS+MacOSX),很难彻底搞懂(iOS没开源,呜呜)。
    官网的解释是说run loop可以用于处理异步事件,很抽象的说法。不罗嗦,先看看NSRunLoop几个常用的方法。
    <pre>
    *+ (NSRunLoop )currentRunLoop; //获得当前线程的run loop
    + (NSRunLoop )mainRunLoop; //获得主线程的run loop
    - (void)run; //进入处理事件循环,如果没有事件则立刻返回。注意:主线程上调用这个方法会导致无法返回(进入无限循环,虽然不会阻塞主线程),因为主线程一般总是会有事件处理。
    - (void)runUntilDate:(NSDate )limitDate; //同run方法,增加超时参数limitDate,避免进入无限循环。使用在UI线程(亦即主线程)上,可以达到暂停的效果。

    **- (BOOL)runMode:(NSString )mode beforeDate:(NSDate )limitDate; //等待消息处理,好比在PC终端窗口上等待键盘输入。一旦有合适事件(mode相当于定义了事件的类型)被处理了,则立刻返回;类同run方法,如果没有事件处理也立刻返回;有否事件处理由返回布尔值判断。同样limitDate为超时参数。
    **- (void)acceptInputForMode:(NSString )mode beforeDate:(NSDate )limitDate; //似乎和runMode:差不多(测试过是这种结果,但确定是否有其它特殊情况下的不同),没有BOOL返回值。
    官网文档也提到run和runUntilDate:会以NSDefaultRunLoopMode参数调用runMode:来处理事件。
    当app运行后,iOS系统已经帮助主线程启动一个run loop,而一般线程则需要手动来启动run loop。
    使用run loop的一个好处就是避免线程轮询的开销,run loop在无事件处理时可以自动进入睡眠状态,降低CPU的能耗。
    </pre>

    比如一般线程轮询的方式为:
    <pre>
    while (condition)
    {
      // waiting for new data
      sleep(1);
      // process current data
    }
    </pre>
    其实这种方式是很能消耗CPU时间片的,如果在UI线程中这样使用还会阻塞UI响应。而改用NSRunLoop来实现,则可大大改善线程的执行效率,而且不会阻塞UI(很神奇,呵呵。有点像javascript,用单线程实现多线程的效果)。上面的例子可以改为:
    <pre>
    while (condition)
    {
      // waiting for new data
      if ([[NSRunLoop currentRunLoop******] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]])
      {
        // process current data
      }
    }
    </pre>
    接下来我们看看具体的例子,包括如何实现线程执行的关联同步(join),以及UI线程run loop的一般使用技巧等。
    假设有个线程A,它会启动线程B,然后等待B线程的结束。NSThread是没有join的方法,用run loop方式实现就比较精巧。
    <pre>
    *NSThread A; //global
    A = [[NSThread alloc] initWithTarget:self selector:@selector(runA) object:nil]; //生成线程A
    [A start]; //启动线程A
    - (void)runA
    {
      [NSThread detachNewThreadSelector:@selector(runB) toTarget:self withObject:nil]; //生成线程B
      while (1)
      {
        if ([[NSRunLoop currentRunLoop] runMode:@"CustomRunLoopMode" beforeDate:[NSDate distantFuture]]) //相当于join
        {
          NSLog(@"线程B结束");
          break;
        }
      }
    }
    - (void)runB
    {
      sleep(1);
      [self performSelector:@selector(setData) onThread:A withObject:nil waitUntilDone:YES modes:@[@"CustomRunLoopMode"]];
    }
    </pre>
    实际运行时,过1秒后线程A也会自动结束。这里用到自定义的mode,一般在UI线程上调用run loop会使用缺省的mode。结合while循环,UI线程就E可以实现子线程的同步运行(具体例子这里不再描述,可参看:
    http://www.cnblogs.com/tangbinblog/archive/2012/12/07/2807088.html)。
    <pre>
    下面罗列调用主线程的run loop的各种方式,读者可以加深理解:
    [[NSRunLoop mainRunLoop] run]; //主线程永远等待,但让出主线程时间片
    [[NSRunLoop mainRunLoop] runUntilDate:[NSDate distantFuture******]]; //等同上面调用
    [[NSRunLoop mainRunLoop] runUntilDate:[NSDate date******]]; //立即返回
    [[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:10.0]]; //主线程等待,但让出主线程时间片,然后过10秒后返回
    [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate: [NSDate distantFuture]]; //主线程等待,但让出主线程时间片;有事件到达就返回,比如点击UI等。
    [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate: [NSDate date******]]; //立即返回
    [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate: [NSDate dateWithTimeIntervalSinceNow:10.0]]; //主线程等待,但让出主线程时间片;有事件到达就返回,如果没有则过10秒返回。
    </pre>

    Q:
    1.主线程的runloop 在做请求 上传 等耗时的操作
    如果 [[NSRunLoop currentRunLoop] 是主线程的 runloop 不断的轮询则会
    就会造成阻塞主线程
    主线程做不了其他的事情 一直轮询

    A:应该新建线程去做完成任务

    相关文章

      网友评论

          本文标题:iOS 同步完成事件

          本文链接:https://www.haomeiwen.com/subject/jmjvnttx.html