Cocoa:如何在执行后台任务时运行模式窗口?
我尝试调用
modalSession=[NSApp beginModalSessionForWindow:conversionWindow];
[NSApp runModalForWindow:conversionWindow];
以获得模式转换窗口,以防止用户与应用程序的其余部分交互,但这似乎也会阻止代码执行。我的意思是上面显示的代码后面的代码根本没有执行。我该如何解决这个问题?我确信这是可能的,因为许多应用程序在执行一些大任务(例如视频转换等)时显示出一些进展......
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
除非绝对必要,否则请不要使用应用程序模式窗口。如果可能的话,使用一张纸。但是,如果必须使用模式对话框,则可以在模式对话框打开时给主运行循环一些时间来运行主运行循环:
如果您有需要主运行循环才能运行的视图,这非常有用(
我想到了 WebView
)。但是,请理解模态会话就是这样,调用
beginModalSessionForWindow:
之后的任何代码都不会执行,直到模态窗口关闭且模态会话结束。这是不使用模式对话框的一个很好的理由。请注意,您不得在上面代码的
while
循环中执行任何重要工作,因为这样您将阻塞模态会话以及主运行循环,这会将您的应用程序变成沙滩球城市。如果你想在后台做一些实质性的事情,你必须使用某种形式的并发,例如使用 NSOperation、GCD 后台队列或只是一个普通的后台线程。
Please don't use an app-modal window unless it's absolutely necessary. Use a sheet if possible. However, if you must use a modal dialog, you can make the main run loop run by giving it some time while the modal dialog is open:
This is very useful if you have views that require the main run loop to operate (
WebView
comes to mind).However, understand that a modal session is just that, and any code after the call to
beginModalSessionForWindow:
will not be executed until the modal window closes and the modal session ends. This is one very good reason not to use modal dialogs.Note that you must not do any significant work in the
while
loop in the code above, because then you will block your modal session as well as the main run loop, which will turn your app into beachball city.If you want to do something substantial in the background you must use some form of concurrency, such as a using
NSOperation
, a GCD background queue or just a plain background thread.如果您希望后台“任务”在模态窗口启动时运行,则需要在另一个线程中启动后台“任务”。但在大多数情况下,最好的解决方案是不使用模式窗口。
You need to start the background "task" in another thread if you want it to run while a modal window is up. But in most cases, the best solution is to not use a modal window.
这就是模态窗口的工作原理:窗口同步呈现,并且在模态窗口会话停止后执行
NSApp.runModal(for: window)
之后的代码。在幕后,模态窗口在特殊的模态事件循环中运行,因此仅处理指定窗口中发生的事件。
在代码中,它确实在 NSApp.runModal(for: window) 处停止执行,但您仍然可以从窗口分派作业。例如,模态窗口上触发下载任务的按钮。
您可以使用:
您认为模态窗口阻止代码执行的一种常见情况可能是:
并且在其他地方尝试使用 GCD 进行分派。例如:
由于
NSApp.runModal(for: window)
不会离开已分派的块,因此在模态窗口被关闭之前,GCD 主队列不会执行后续块。为了避免此阻塞问题,您可以:
DispatchQueue.main
中调用NSApp.runModal(for: window)
。对于第二个解决方案,我为自己做了一个方便的助手:
这样当GCD主队列被阻塞时,您可以使用在主线程上调用一些代码
来阅读更多内容,这个文章帮助了我。
That is how a modal window works: the window is presented synchronously, and the code after
NSApp.runModal(for: window)
is executed after the modal window session is stopped.Under the hood, the modal window runs in a special modal event loop, so that only the events happen in the specified window are processed.
In code, it does stop the execution at the point of
NSApp.runModal(for: window)
, but you can still dispatch jobs from the window. For example, a button on the modal window that triggers a download task.You can use:
One common scenario that you feel the modal window blocks code execution can be:
and somewhere else tries to dispatch using GCD. For example:
Because
NSApp.runModal(for: window)
doesn't leave the dispatched block, the GCD main queue won't execute following blocks until the modal window is dismissed.To avoid this blocking issue, you could:
NSApp.runModal(for: window)
inDispatchQueue.main
.For the 2nd solution, I made a convenient helper for myself:
So that when the GCD main queue is blocked, you can use to call some code on the main thread
To read more, this article helped me.