NSApp nextEventMatchingMask与dispatch内的dispatch

时间:2014-09-03 15:17:56

标签: objective-c

我目前正在开发一个运行自己的事件循环的应用程序。如果我在没有从另一个调度中排队时使用调度异步,则其块正确运行。

示例:

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"This should appear!");
        });

for (;;)
{
   NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask
                                                untilDate:[NSDate distantPast]
                                                   inMode:NSDefaultRunLoopMode
                                                  dequeue:YES];

    [NSApp sendEvent:event];
 }

如果我运行它,将按预期调用日志。

但是,让我说我把这个调度包裹起来,就像这样:

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)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"This should appear!");
    });
    for (;;)
    {
        NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask
                                            untilDate:[NSDate distantPast]
                                               inMode:NSDefaultRunLoopMode
                                              dequeue:YES];

        [NSApp sendEvent:event];
    }
});

如果我运行此代码,则不会执行日志。我可以想象,因为extEventMatchingMask:在一个排队的块中被调用,它将无法处理将来调度的块。但奇怪的是,如果我使用performSelector:它甚至会在排队的块中执行。

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)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"This should appear!");
        });

        [self performSelector:@selector(logAppear) withObject:nil afterDelay:2];

        for (;;)
        {
            NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask
                                                untilDate:[NSDate distantPast]
                                                   inMode:NSDefaultRunLoopMode
                                                  dequeue:YES];

            [NSApp sendEvent:event];
        }
    });

-(void) logAppear {
    NSLog(@"This should appear!");
}

如果我运行此示例,将按预期调用方法logAppear。

所以,简而言之,我想问为什么第二种情况不起作用,以及如何(如果可能的话)我可以在一个能够运行调度块的入队块中运行事件循环。

1 个答案:

答案 0 :(得分:0)

经过一些实验后,我意识到我需要做的是确保在任何排队的块之外执行该事件循环。我们可以通过将循环放在方法中并确保它由performSelector调用来完成此操作。

示例:

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)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"This should appear!");
        });

        [self performSelector:@selector(logAppear) withObject:nil afterDelay:2];

        [self performSelector:@selector(mainLoop) withObject:nil afterDelay:0];

    });


-(void) mainLoop {
    for (;;)
    {
        NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask
                                            untilDate:[NSDate distantPast]
                                               inMode:NSDefaultRunLoopMode
                                              dequeue:YES];

        [NSApp sendEvent:event];
    }
}

-(void) logAppear {
    NSLog(@"This should appear!");
}

通过运行此示例,我们现在可以按预期获得两个日志