从 ShouldTerminate 返回 NSTerminateLater 后,NSApplicationDelegate 没有延迟调用?

Posted

技术标签:

【中文标题】从 ShouldTerminate 返回 NSTerminateLater 后,NSApplicationDelegate 没有延迟调用?【英文标题】:NSApplicationDelegate not getting delayed call after returning NSTerminateLater from ShouldTerminate? 【发布时间】:2018-04-01 22:29:44 【问题描述】:

我在 Xcode 中创建了一个 Mac 应用程序。我所做的唯一代码更改是在应用程序委托中。现在它的全部内容如下:

#import "AppDelegate.h"

@interface AppDelegate ()

@end

@implementation AppDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification 


- (void) readyToTerminate: (id) sender 
  NSLog(@"Ready to terminate");
  [NSApplication.sharedApplication replyToApplicationShouldTerminate:YES];


- (NSApplicationTerminateReply) applicationShouldTerminate:(NSApplication *)sender 
  [self performSelector:@selector(readyToTerminate:) withObject:self afterDelay:1.0];
  NSLog(@"Later please");
  return NSTerminateLater;


- (void)applicationWillTerminate:(NSNotification *)aNotification 
  NSLog(@"Terminating");


@end

当我运行应用程序时,我确实看到了一个窗口。然后我按命令-Q 终止。输出是:

2018-04-01 17:20:03.110563-0500 TerminateThisApp[3336:364401] Unknown Window 
class (null) in Interface Builder file,
     creating generic Window instead
2018-04-01 17:20:06.929175-0500 TerminateThisApp[3336:364401] Later please

所以 readyToTerminate: 没有被调用。为什么会这样?我不明白。

为了它的价值,我尝试了一个同样没有结果的 NSTimer。我还尝试以与 didFinishLaunching 相同的方式调用 readyToTerminate。在这种情况下,readyToTerminate 确实触发了(并且应用程序没有终止,这很好)。

发生了什么事?

【问题讨论】:

【参考方案1】:

我刚刚使用您的代码在 Xcode 9.3 上构建了一个快速的 macOS 应用程序,并注意到选择器引发了启动服务异常(当您在调试器中单步执行代码时,请增加您的时间以便清楚地看到它)。

如果您查看Console 应用程序并按您的应用程序名称进行过滤(例如,我使用了SO-49603218),您是否会看到这样的条目:

default 09:44:00.031347 +1000   SO-49603218 LSExceptions shared instance invalidated for timeout.
default 09:44:55.906555 +1000   SO-49603218 Later please

我认为应用程序引用计时器所指的可能是 self 正在失效。这可能与您回复 NSTerminateLater 时将运行循环切换到 NSModalPanelRunLoopMode 有关

如果您更改为NSTerminateCancel,那么您的readyToTerminate: 方法将被调用。

default 09:55:28.851246 +1000   SO-49603218 Later please
default 09:55:28.864566 +1000   SO-49603218 LSExceptions shared instance invalidated for timeout.
default 09:55:29.851891 +1000   SO-49603218 Ready to terminate

注意LSException 仍然被抛出 ?

我认为在阅读了有关Anatomy of a Run Loop documentation 的更多信息后,问题是performSelector: 调用是在NSDefaultRunLoopMode 上进行的,因此在您返回该运行模式之前不会调用它。从文档中,在 Timer Sources 下:

与输入源一样,计时器与运行循环的特定模式相关联。 如果计时器不在运行循环当前监控的模式下,它不会触发,直到您以计时器支持的模式之一运行运行循环。

【讨论】:

以上是关于从 ShouldTerminate 返回 NSTerminateLater 后,NSApplicationDelegate 没有延迟调用?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 xib 文件在单元格中 rtl UITextField?

从 main 返回零是不是必要,从 main 的返回值如何有用?

从函数返回“本地”字符*与从函数返回“本地”int*之间的区别[重复]

如何从异步调用返回响应

如何从异步调用返回响应

如何从异步调用返回响应