我正在使用标准的运行循环(由XCode创建)App进行测试。我的应用程序有2个按钮:
Start Loop
- 以某种模式启动runloop(参见下面的代码); Stop Loop
- 更改self.stop
标志以停止runloop。`
- (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
按钮时,我的应用程序正在冻结:
。
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);
}
有一个问题:“为什么我以这种方式运行默认运行循环模式或其他一些模式,我无法接收事件?”
谢谢你的建议。
答案 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);
}