拦截NSDocument关闭:在「是否保存更改?」面板弹出前处理子窗口变更
解决NSDocument关闭前检查子窗口变更的问题
我明白你的痛点——默认的-[Document canCloseDocumentWithDelegate:shouldCloseSelector:contextInfo:]确实只会在文档本身被标记为变更(通过updateChangeCount:)时才触发确认流程,完全忽略子窗口的状态。要解决这个问题,我们需要绕过这个限制,强制在任何关闭场景下都先检查子窗口的变更,下面是具体的实现方案:
1. 拦截文档窗口的关闭事件
NSDocument本身就是其窗口的默认代理,所以我们可以直接在Document类里重写windowShouldClose:方法,在这里插入子窗口的检查逻辑:
- (BOOL)windowShouldClose:(id)sender { // 第一步:检查所有子窗口的变更状态 BOOL hasUnsavedChildChanges = [self hasUnsavedChildWindowChanges]; if (hasUnsavedChildChanges) { // 弹出提示框询问用户操作 NSAlert *alert = [[NSAlert alloc] init]; [alert setMessageText:@"子窗口存在未保存的变更"]; [alert setInformativeText:@"请选择后续操作:"]; [alert addButtonWithTitle:@"保存并关闭"]; [alert addButtonWithTitle:@"放弃变更并关闭"]; [alert addButtonWithTitle:@"取消"]; NSInteger result = [alert runModal]; switch (result) { case NSAlertFirstButtonReturn: // 先处理子窗口的保存逻辑,再允许关闭 [self saveAllChildWindows]; return [super windowShouldClose:sender]; case NSAlertSecondButtonReturn: // 用户确认放弃,直接允许关闭 return YES; default: // 用户取消关闭 return NO; } } // 子窗口无变更,走默认的文档关闭逻辑 return [super windowShouldClose:sender]; }
其中hasUnsavedChildWindowChanges是你需要自己实现的方法,用来遍历所有子窗口、检查它们的变更状态;saveAllChildWindows则是处理子窗口内容保存的逻辑。
2. 覆盖直接调用close的场景
除了点击窗口关闭按钮,用户还可能通过菜单(File -> Close)或代码直接调用close方法关闭文档,这时候我们需要重写Document的close方法来覆盖这种情况:
- (void)close { BOOL hasUnsavedChildChanges = [self hasUnsavedChildWindowChanges]; if (hasUnsavedChildChanges) { NSAlert *alert = [[NSAlert alloc] init]; [alert setMessageText:@"子窗口存在未保存的变更"]; [alert setInformativeText:@"请选择后续操作:"]; [alert addButtonWithTitle:@"保存并关闭"]; [alert addButtonWithTitle:@"放弃变更并关闭"]; [alert addButtonWithTitle:@"取消"]; NSInteger result = [alert runModal]; switch (result) { case NSAlertFirstButtonReturn: [self saveAllChildWindows]; [super close]; break; case NSAlertSecondButtonReturn: [super close]; break; default: // 用户取消,不执行关闭 return; } } else { [super close]; } }
3. 关键注意事项
- 要给每个子窗口维护独立的变更状态标记,比如在子窗口的内容修改时,设置一个
isDirty的BOOL变量,这样hasUnsavedChildWindowChanges可以快速遍历判断。 - 如果子窗口的保存需要异步操作(比如写入文件),要注意调整逻辑,等待保存完成后再执行文档关闭。
内容的提问来源于stack exchange,提问作者fbitterlich
相关产品推荐
相关产品推荐

