运行循环不会继续事件

时间:2014-02-27 12:24:58

标签: cocoa core-foundation nsrunloop

我正在使用标准的运行循环(由XCode创建)App进行测试。我的应用程序有2个按钮:

  1. Start Loop - 以某种模式启动runloop(参见下面的代码);
  2. Stop Loop - 更改self.stop标志以停止runloop。
  3. `

    - (IBAction)stopLoop:(id)sender
    {
        self.stop = YES;
    }
    
    - (IBAction)startLoop:(id)sender
    {
        self.stop = NO;
        do
        {
            [[NSRunLoop currentRunLoop] runMode:runLoopMode beforeDate:runLoopLimitDate];
            if (self.stop)
            {
                break;
            }
        } while (YES);
    }
    

    `

    其中:
    1. runLoopMode是预定义模式之一(我尝试各自,默认,事件跟踪,模态,连接)。
    2. runLoopLimitDate [NSDate distantFuture],或[NSDate distantPast],或关闭功能。
    3. self.stop标志安装在其他方法中,按钮调用。

    就是这样,我的应用程序没有任何其他代码。

    AFAIU,runloop模式是一组事件源。因此,如果我在某种模式下运行runloop,runloop将继续执行与此模式关联的事件源。
    默认情况下,Cocoa以默认模式运行runloop,并且所有事件都会大量进行。但是当用户按下startLoop按钮时,我的应用程序正在冻结:
    freezed app
    startLoop方法永远不会打破这个无限循环。应用程序不会向我发送任何事件,因此UI冻结和用户无法按stopLoop按钮。如果我运行核心基金会同行,也会遇到同样的问题。

    但是,当我尝试通过NSApplication(NSWindow)方法nextEventMatchingMask:untilDate:inMode:dequeue:接收事件并通过相同模式时,我会收到UI事件。

    - (IBAction)startLoop:(id)sender
    {
        self.stop = NO;
        do
        {
            NSEvent *event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:nil inMode:NSEventTrackingRunLoopMode dequeue:YES];
            if (event == nil)
            {
                break;
            }
            [NSApp sendEvent:event];
            if (self.stop)
            {
                break;
            }
        } while (YES);
    }
    

    有一个问题:“为什么我以这种方式运行默认运行循环模式或其他一些模式,我无法接收事件?”
    谢谢你的建议。

3 个答案:

答案 0 :(得分:2)

您假设在NSDefaultRunMode中运行NSRunLoop会处理用户输入事件,例如按键或鼠标单击。我认为不是这样的。

NSApplication使用nextEventMatchingMask:untilDate:inMode:dequeue:从事件中获取事件。通过运行循环,就像你没有真正获取事件队列的任何事件一样。

云你尝试这样的事情:

- (IBAction)startLoop:(id)sender
{
    do
    {
        NSEvent *event = [NSApp nextEventMatchingMask:NSAnyEventMask];
        [NSApp sendEvent:event];

        if (self.stop)
        {
            break;
        }
    } while (YES);
}

(尚未对此进行测试)。

答案 1 :(得分:0)

如果您在应用中使用以下代码替换-startLoop:方法,会发生什么?

- (NSString *) debugLogRunLoopInfo(BOOL didRun)
{
    NSLog (@"didRun? %@, runMode: %@, dateNow: %@, limitDate: %@",
        didRun ? @"YES" : @"NO",
        runLoopMode,
        [NSDate date],
        limitDate);
}

- (IBAction)startLoop:(id)sender
{
    BOOL didRun = NO;
    do
    {
        didRun = [[NSRunLoop currentRunLoop] runMode:runLoopMode beforeDate:runLoopLimitDate];
        [self debugLogRunLoopInfo:didRun];
        if (self.stop)
        {
            break;
        }
    } while (YES);
}

答案 2 :(得分:0)

-[NSRunLoop runUntilDate:]方法在NSDefaultRunLoopMode中旋转runloop。由于您希望尝试使用runloop模式,因此可以尝试以下代码。

我已经实现了一个-myRunLoopUntilDate:runMode:方法来执行runUntilDate:要记录的操作,但允许您指定一个runloop模式。

所有这些都是在我的文本编辑器中编译的(即根本没有编译),因此需要注意。

- (NSString *) debugLogRunLoopInfo(BOOL didRun)
{
    NSLog (@"didRun? %@, runMode: %@, dateNow: %@, limitDate: %@",
        didRun ? @"YES" : @"NO",
        runLoopMode,
        [NSDate date],
        limitDate);
}

- (void) myRunLoopUntilDate:(NSDate *)limitDate runMode:(NSString *)runLoopMode
{
    BOOL didRun = NO;
    do {
        didRun = [[NSRunLoop currentRunLoop] runMode:runLoopMode beforeDate:limitDate];
        [self debugLogRunLoopInfo:didRun];
    } while (didRun && ([limitDate timeIntervalSinceNow] > 0));
}

- (IBAction)startLoop:(id)sender
{
    BOOL didRun = NO;
    do
    {
        [self myRunLoopUntilDate:runLimitDate runMode:runLoopMode];
        if (self.stop)
        {
            break;
        }
    } while (YES);
}