Как программно завершить работу NSApp без кодирования состояния окна?
Все приложения OS X, которые поддерживают NSWindowRestoration
можно закрыть, выбрав пункт меню "Выйти и закрыть все окна" (Option-Command Q). Это отключает восстановление состояния, и в следующий раз, когда вы откроете приложение, все окна будут в положении по умолчанию.
Пункт меню запускает terminate:
метод на NSApplication
, Но так же, как и обычное меню "Закрыть приложение" (команда Q).
Как я могу сделать "Выйти и закрыть все окна" программно? Мне действительно нужно закрыть все окна самостоятельно, а затем позвонить terminate:
?
Как Apple волшебным образом решает, что делать, если оба действия связаны с одним и тем же terminate:
метод?
2 ответа
Кажется, не существует отличного способа сделать это. Возможно, вы захотите сообщить об ошибке в запрос Apple (вместе с объяснением того, зачем вам это нужно).
Как Apple волшебным образом решает, что делать, если оба действия связаны с одним и тем же
terminate:
метод?
Ну, глядя на разборку AppKit, кажется, что -[NSApplication terminate:]
проверяет, является ли отправитель экземпляром NSMenuItem
, Если это так, он проверяет, если его userInterfaceItemIdentifier
равно @"NSAlternateQuitMenuItem"
,
Вы могли бы, я полагаю, создать фиктивный пункт меню с этим идентификатором и передать его в качестве отправителя -terminate:
, хотя, поскольку это зависит от деталей реализации, он может сломаться в любое время.
Другим управляющим фактором является настройка "Системные настройки"> "Основные"> "Закрыть окна при выходе из приложения". Это соответствует ключу пользователя по умолчанию NSAlternateQuitMenuItem
Хотя, опять же, это деталь реализации. Похоже, что вы могли бы установить это до вызова -terminate:
а затем, в -applicationWillTerminate:
Метод делегата, удалите этот параметр. (Ваши изменения будут связаны с вашим приложением. Они не будут влиять на другие приложения или настройку в Системных настройках.) Конечно, вам нужно будет убедиться, что внезапное завершение отключено, чтобы получить этот вызов метода делегата.
NSApplication может быть подклассом.
Задайте имя основного класса в информации о цели сборки, а затем переопределите-terminate:
@interface MyApplication : NSApplication
@end
@implementation MyApplication
- (void) terminate:(id)sender
{
if ([sender isKindOfClass:NSMenuItem.class])
{
BOOL alwaysKeeps = [NSUserDefaults.standardUserDefaults boolForKey:@"NSQuitAlwaysKeepsWindows"];
NSMenuItem* item = sender;
item.identifier = alwaysKeeps ? @"NSAlternateQuitMenuItem" : @"";
}
[super terminate:sender];
}
@end
Вы можете проверить отправителя (NSMenuItem) в отладчике и увидеть этого участника._uiid
устанавливается на @"NSAlternateQuitMenuItem", когда вы удерживаете клавишу Option при выходе.
В зависимости от предпочтений пользователя системы вам необходимо либо добавить, либо удалить идентификатор.
Я бы использовал эту технику только для противоположного эффекта; всегда кодировать восстанавливаемое состояние открытых окон, игнорируя предпочтения пользователя системы. В противном случае я бы просто поставил-terminate
действие где-то в цепочке ответчика, чтобы закрыть все окна до того, как NSApplication получит сообщение:
- (void) terminate:(id)sender
{
for (NSWindow* window in NSApp.windows)
{
[window close];
}
[NSApp terminate:sender];
}