Cocoa: how to run a modal window while performing

2019-02-15 17:36发布

问题:

I've tried calling

modalSession=[NSApp beginModalSessionForWindow:conversionWindow];
[NSApp runModalForWindow:conversionWindow];

in order to get a modal conversionWindow that prevents the user to interact with the rest of the application, but this also seems to block code execution. What I mean is that the code that comes after the code shown above isn't executed at all. How can I fix this? I'm sure this is possible because many applications show some progress while performing some big task, like video conversion etc...

回答1:

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:

NSModalSession session = [NSApp beginModalSessionForWindow:[self window]];
int result = NSRunContinuesResponse;

while (result == NSRunContinuesResponse)
{
    //run the modal session
    //once the modal window finishes, it will return a different result and break out of the loop
    result = [NSApp runModalSession:session];

    //this gives the main run loop some time so your other code processes
    [[NSRunLoop currentRunLoop] limitDateForMode:NSDefaultRunLoopMode];

    //do some other non-intensive task if necessary
}

[NSApp endModalSession:session];

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.



回答2:

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.