dispatch_after块未运行 讨论

请考虑以下简单示例:

- (void)viewDidLoad
{
    [super viewDidLoad];

dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t)(2 * NSEC_PER_SEC)),dispatch_get_main_queue(),^{

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t)(3 * NSEC_PER_SEC)),^{
        NSLog(@"BLOCK!!!");

    });

    while (YES)
    {
        [[NSRunLoop currentRunLoop] runmode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:1]];
        NSLog(@"RUN LOOP");
    }
});
}

传递到dispatch_after的第二个调用(3秒)中的块未触发。但是,如果我不使用前dispatch_after(2秒),那么它将按预期工作。为什么?

我知道,如果我在内部运行NSRunLoop的情况下删除while循环,则它可以正常工作,但是我需要在那儿循环

ziruozi 回答:dispatch_after块未运行 讨论

我在示例中没有看到任何注册的输入源。我认为调度不算作输入源。

在这种情况下,-runMode:beforeDate:将立即返回NO。您设置的无限循环只会旋转而不会退出当前运行。它永远不会回到运行循环的顶部,也永远不会处理任何调度队列。

runMode:beforeDate:中,行为被定义。

  

讨论

     

如果没有输入源或计时器附加到运行循环,则此方法立即退出并返回NO;否则,返回0。否则,它将在处理第一个输入源或达到limitDate之后返回。从运行循环中手动删除所有已知的输入源和计时器并不能保证运行循环将立即退出。 macOS可能会根据需要安装和删除其他输入源,以处理针对接收者线程的请求。因此,这些源可能会阻止运行循环退出。

,

您拥有其中的代码

  • 安排(2,100) * (100,2)在主队列上运行;但是然后
  • 使用dispatch_after循环阻塞主队列,该循环重复调用while

这只是阻止主线程执行任何未直接从主NSRunLoop调用的操作。

此问题有三种解决方案:

  1. 您可以通过将NSRunLoop循环的代码调度到全局(即后台)队列来解决此问题:

    while

    这项技术是我们在GCD之前的时代所做的一种排列。如今,这在很大程度上变得毫无用处。效率太低了。

  2. 您可以使用从- (void)viewDidLoad{ [super viewDidLoad]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t)(2 * NSEC_PER_SEC)),dispatch_get_global_queue(QOS_CLASS_DEFAULT,0),^{ NSLog(@"OUTER"); dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t)(3 * NSEC_PER_SEC)),dispatch_get_main_queue(),^{ NSLog(@"INNER!!!"); }); while (true) { [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:1]]; } }); } 计划并运行的NSTimer,因此,即使您仍在阻塞主队列,至少计时器也会触发。

    NSRunLoop

    这实际上不是解决问题的方法(您仍在阻止主线程阻止未从- (void)viewDidLoad{ [super viewDidLoad]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW,^{ NSLog(@"OUTER"); [NSTimer scheduledTimerWithTimeInterval:3 repeats:false block:^(NSTimer * _Nonnull timer) { NSLog(@"INNER!!!"); }]; while (true) { [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:1]]; } }); } 本身运行的任何线程),但说明了运行循环的性质。

  3. 或者,显然,最好是删除NSRunLoop循环:

    while

最重要的是,如今,您几乎永远不会在线程(或其运行循环)上旋转。它的效率极低,GCD提供了更为优雅的方法来达到预期的效果。

本文链接:https://www.f2er.com/3158604.html

大家都在问