代码之家  ›  专栏  ›  技术社区  ›  William Jockusch

NSApplicationDelegate在从ShouldTerminate返回NSTerminater后没有收到延迟呼叫?

  •  0
  • William Jockusch  · 技术社区  · 7 年前

    我在Xcode中创建了一个Mac应用程序。我所做的唯一代码更改是在app delegate中。现在,它的整体内容如下:

    #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
    

    当我运行应用程序时,我确实看到了一个窗口。然后我点击command-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 回复  |  直到 7 年前
        1
  •  1
  •   Craig    7 年前

    我刚刚用您的代码在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 正在失效。这可能与运行循环切换到 NSModalPanelRunLoopMode 当您回复时 NSTerminateLater

    如果您更改为 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 因此,在返回到该运行模式之前不会调用它。从文档中,在 计时器源 :

    与输入源一样,计时器与跑步循环的特定模式相关联。 如果计时器未处于运行循环当前监视的模式,则在您以计时器支持的模式之一运行运行循环之前,它不会启动。