如何在 Cocoa 中实现自定义 NSApplication Terminate: 行为?
我正在尝试在 Cocoa 应用程序中实现自定义终止行为。通常,当我的应用程序正常退出时,它会执行最终运行时数据库清理,然后退出。每当调用 [NSApp Terminate:aSender]
时,都会在 AppDelegate(NSApplication
的委托)内部发生这种情况:
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{
// database cleanup...
return NSTerminateNow;
}
如果在运行时发生错误(例如,数据库文件被删除),我会呈现向用户报告错误,并为他们提供恢复(将文件放回并重试)或退出的选项。如果选择“退出”,我想退出应用程序并完全跳过数据库清理,因为它不再可能了。本质上,我想要这样的东西:
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{
BOOL gracefulTermination = ...;
if (gracefulTermination == YES)
{
// Database cleanup....
}
return NSTerminateNow;
}
当然,问题是获取 gracefulTermination 的值。
有没有办法在调用 terminate:
时将自定义变量传递给 NSApp
,例如 infoDict,然后在 applicationShouldTerminate:
内接收它?
如果没有,是否有更好的方法来完成自定义终止行为?
据我所知,当 terminate:
被其他对象调用时,会发生这种情况:
[NSApp Terminate:self];
由 foo(又名自我)。- NSApp 发送其委托:
[aDelegate applicationShouldTerminate:self];
(self 是 NSApp,而不是 foo)。 - aDelegate 接收消息并执行
applicationShouldTerminate:
(如果已实现)。
foo 似乎消失在某个地方,当 aDelegate 收到消息时,它已经永远消失了,只有 NSApp
作为发送者出现。这阻止我将 foo 内部的 infoDict 或者只是一个普通的 infoDict 传递给包含自定义 terminate:
行为的Delegate。
我知道可以在不使用 [NSApp Terminate:...]
和 exit()
之类的情况下退出。尽管从我读到的内容来看,这是不受欢迎的,因为这对可可来说不符合犹太教规。另外,它还可以防止在 applicationShouldTerminate:
内部发生任何其他清理操作,即使在非正常退出期间也不应跳过这些操作。
I'm attempting to implement custom termination behavior in a Cocoa application. Normally when my application exits gracefully, it performs final-runtime database cleanup and then exits. This occurs inside AppDelegate (delegate of NSApplication
) whenever [NSApp terminate:aSender]
is called:
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{
// database cleanup...
return NSTerminateNow;
}
If an error occurs during runtime (e.g. the database file was deleted), I present the error to the user, and give them the option to Recover (put the file back and try again), or to Quit. If Quit is selected, I want to exit the app skipping database cleanup all-together since it's no longer possible. In essence, I'd like something like this:
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{
BOOL gracefulTermination = ...;
if (gracefulTermination == YES)
{
// Database cleanup....
}
return NSTerminateNow;
}
The problem, of course, is getting the value for gracefulTermination.
Is there a way to pass a custom variable to NSApp
when terminate:
is called, such as an infoDict, and then receive it inside applicationShouldTerminate:
?
If not, is there a better way to accomplish custom termination behavior?
As far as I know, when terminate:
is called by some other object, this happens:
[NSApp terminate:self];
is called by foo (a.k.a. self).- NSApp sends its delegate:
[aDelegate applicationShouldTerminate:self];
(self is NSApp, not foo). - aDelegate receives the message and executes
applicationShouldTerminate:
if implemented.
foo appears to disappear somewhere, and by the time aDelegate gets the message, it's gone for good and only NSApp
appears as sender. This prevents me from passing an infoDict inside of foo, or just a plain infoDict, to aDelegate containing custom terminate:
behavior.
I am aware that it's possible to exit without using [NSApp terminate:...]
with something like exit()
. Though from what I've read this is frowned down upon since it's not kosher for Cocoa. Plus it would also prevent any other cleanup operations from occurring inside applicationShouldTerminate:
, operations which shouldn't be skipped even during a non-graceful exit.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
理想的解决方案是以应用程序委托可以判断是否允许终止的方式构建应用程序。
假设您的应用程序委托不可能以任何其他方式访问此信息(例如,哪个对象触发终止会影响它是否会发生),这似乎是最简单的解决方案:子类 NSApplication,给它一个
terminationInfo 属性并覆盖
terminate:
以设置此属性并调用 super.The ideal solution would be to structure your app in such a way that the app delegate can tell whether it's allowed to terminate.
Assuming it isn't possible for your application delegate to access this information any other way (say, which object triggered termination affects whether it can happen), this seems like the simplest solution: Subclass NSApplication, give it a
terminationInfo
property and overrideterminate:
to set this property and call super.