等待 [NSAlert beginSheetModalForWindow:...];
当我显示这样的 NSAlert 时,我立即得到响应:
int response;
NSAlert *alert = [NSAlert alertWithMessageText:... ...];
response = [alert runModal];
问题是这是应用程序模式,而我的应用程序是基于文档的。 我使用工作表在当前文档的窗口中显示警报,如下所示:
int response;
NSAlert *alert = [NSAlert alertWithMessageText:... ...];
[alert beginSheetModalForWindow:aWindow
modalDelegate:self
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:)
contextInfo:&response];
//elsewhere
- (void) alertDidEnd:(NSAlert *) alert returnCode:(int) returnCode contextInfo:(int *) contextInfo
{
*contextInfo = returnCode;
}
唯一的问题是 beginSheetModalForWindow:
立即返回,因此我无法可靠地向用户询问问题并等待响应。 如果我可以将任务分成两个区域,这就不是什么大问题,但我不能。
我有一个循环处理大约 40 个不同的对象(位于树中)。 如果一个对象失败,我希望显示警报并询问用户是否继续或中止(在当前分支继续处理),但由于我的应用程序是基于文档的,因此 Apple 人机界面指南规定在警报发生时使用工作表具体到一个文档。
如何显示警报表并等待响应?
When I display an NSAlert like this, I get the response straight away:
int response;
NSAlert *alert = [NSAlert alertWithMessageText:... ...];
response = [alert runModal];
The problem is that this is application-modal and my application is document based. I display the alert in the current document's window by using sheets, like this:
int response;
NSAlert *alert = [NSAlert alertWithMessageText:... ...];
[alert beginSheetModalForWindow:aWindow
modalDelegate:self
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:)
contextInfo:&response];
//elsewhere
- (void) alertDidEnd:(NSAlert *) alert returnCode:(int) returnCode contextInfo:(int *) contextInfo
{
*contextInfo = returnCode;
}
The only issue with this is that beginSheetModalForWindow:
returns straight away so I cannot reliably ask the user a question and wait for a response. This wouldn't be a big deal if I could split the task into two areas but I can't.
I have a loop that processes about 40 different objects (that are in a tree). If one object fails, I want the alert to show and ask the user whether to continue or abort (continue processing at the current branch), but since my application is document based, the Apple Human Interface Guidelines dictate to use sheets when the alert is specific to a document.
How can I display the alert sheet and wait for a response?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
我们在
NSAlert
上创建了一个类别来同步运行警报,就像应用程序一样- 模态对话框:代码可通过 GitHub 获取,为了完整起见,下面发布了当前版本。
头文件
NSAlert+SynchronousSheet.h
:实现文件
NSAlert+SynchronousSheet.m
:We created a category on
NSAlert
to run alerts synchronously, just like application-modal dialogs:The code is available via GitHub, and the current version posted below for completeness.
Header file
NSAlert+SynchronousSheet.h
:Implementation file
NSAlert+SynchronousSheet.m
:这是一个解决该问题的 NSAlert 类别(正如 Philipp 所建议的,并由 Frederick 提出并由 Laurent P. 改进的解决方案:我使用代码块而不是委托,因此它再次被简化)。
Here is a NSAlert category that solves the issue (as suggested by Philipp with the solution proposed by Frederick and improved by Laurent P.: I use a code block instead of a delegate, so it is simplified once again).
解决方案是在beginSheetModalForWindow之后调用
。 此外,您需要实现一个委托来捕获“对话框已关闭”操作,并调用 [NSApp stopModal] 作为响应。
The solution is to call
after beginSheetModalForWindow. Also, you need to implement a delegate that catches the "dialog has closed" action, and calls [NSApp stopModal] in response.
以防万一有人来寻找这个(我就是这样做的),我用以下方法解决了这个问题:
然后同步运行 NSAlert 就这么简单:
请注意,正如所讨论的那样,可能会出现重入问题,因此执行此操作时要小心。
Just in case anyone comes looking for this (I did), I solved this with the following:
Then running an NSAlert synchronously is as simple as:
Note there is potential for re-entrancy issues as discussed, so be careful if doing this.
不幸的是,您在这里无能为力。 您基本上必须做出决定:重新架构您的应用程序,以便它可以以异步方式处理对象,或者使用未经批准、已弃用的架构来呈现应用程序模式警报。
如果不知道有关您的实际设计以及如何处理这些对象的任何信息,则很难提供任何进一步的信息。 不过,我的脑海中浮现出一些想法可能是:
然而,这对于您的需要来说可能确实过于复杂。 在这种情况下,我的建议是仅使用已弃用的用法,但这实际上取决于您的用户需求。
Unfortunately, there is not much you can do here. You basically have to make a decision: re-architect your application so that it can process the object in an asynchronous manner or use the non-approved, deprecated architecture of presenting application modal alerts.
Without knowing any information about your actual design and how you processes these objects, it's hard to give any further information. Off the top of my head, though, a couple of thoughts might be:
This may be really over-complicated for what you need, however. In that case, my recommendation would be to just go with the deprecated usage, but it really depends on your user requirements.
斯威夫特5:
Swift 5:
这是我的答案:
创建一个全局类变量'NSIntegeralertReturnStatus'
希望它会有所帮助,
干杯
——汉斯
here is my answer:
Create a global class variable 'NSInteger alertReturnStatus'
Hope it'll be of some help,
Cheers
--Hans
这是上面 Laurent 等人的版本,已翻译为 Xcode 6.4 的 Swift 1.2(今天的最新工作版本)并在我的应用程序中进行了测试。 感谢所有为这项工作做出贡献的人! 苹果的标准文档没有给我任何关于如何解决这个问题的线索,至少在我能找到的任何地方都没有。
我仍然有一个谜:为什么我必须在最终函数中使用双感叹号。 NSApplication.mainWindow 应该只是一个可选的 NSWindow (NSWindow?),对吧? 但编译器给出了显示的错误,直到我使用第二个“!”。
This is the version of Laurent, et al., above, translated into Swift 1.2 for Xcode 6.4 (latest working version as of today) and tested in my app. Thanks to all those who contributed to make this work! The standard documentation from Apple gave me no clues as to how go about this, at least not anywhere that I could find.
One mystery remains to me: why I had to use the double exclamation point in the final function. NSApplication.mainWindow is supposed to be just an optional NSWindow (NSWindow?), right? But the compiler gave the error shown until I used the second '!'.
与 Windows 不同,我不相信有办法阻止模式对话框。 输入(例如用户单击按钮)将在主线程上处理,因此无法阻止。
对于您的任务,您必须将消息向上传递到堆栈,然后从上次中断的地方继续。
Unlike Windows I don't believe there's a way to block on modal dialogs. The input (e.g. the user clicking a button) will be processed on your main thread so there's no way of blocking.
For your task you will either have to pass the message up the stack and then continue where you left off.
当一个对象失败时,停止处理树中的对象,记下哪个对象失败(假设有一个订单,并且您可以从上次中断的地方继续),然后扔掉该表。 当用户关闭工作表时,让
didEndSelector:
方法从其停止的对象再次开始处理,或不开始处理,具体取决于returnCode
。When one object fails, stop processing the objects in the tree, make a note of which object failed (assuming that there is an order and you can pick up where you left off), and throw up the sheet. When the user dismisses the sheet, have the
didEndSelector:
method start processing again from the object that it left off with, or don't, depending on thereturnCode
.您可以使用
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
:希望有帮助。
You can use
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
:Hope that helps.