showWindow: shows window too late

When my app opens a big document, this can involve extensive calculations, which can take a few seconds to complete. Before launching these calculations, if the file is above a certain size, my readFromURL:ofType:error: method opens a panel with a simple indeterminate progress bar and a few words, just to reassure the user that something is going on in the background before the document window appears.


I open this panel by sending a simple showWindow: message to a window controller that is a member of my app controller (the same panel is reused for all documents), and I close the panel after the calculations are finished.


Until El Capitán, this worked perfectly. With El Capitán the panel doesn’t appear at all. If I comment out the line of code that closes the panel, then the panel appears (and stays) at the moment the document window appears(after all the calculations are done), which is too late!

Other panels that the user can open once the document window has been displayed open normally.


How can I fix that?

Answered by QuinceyMorris in 79285022

Well, readFromURL is either called on the main thread or it isn't. If it isn't, it can't do things like showing windows, since UI-related stuff has to be done on the main thread. If it is on the main thread, then it's going to be blocking the main thread, so UI updates may be delayed in their effect until the blockage is cleared. Either way, you're in trouble, and there's no predicting what the user might see. (In particular, the fact that it used to seem to work OK doesn't demonstrate that your approach was correct.)


If you want to solve this properly, you should probably start by moving your mutli-second calculations to a background thread, either using NSOperation or GCD. Yes, that means if you do nothing else, your document window will open before the data is available. So, step 2, you must either design your window so that it's blank or shows a placeholder until the data is ready, or you must delay the opening of that window until the data is ready.


For the latter, you can override NSDocument's 'makeWindowControllers' method (which is called on the main thread). Perhaps in there you can test whether the data is ready, and if not open a progress panel instead of the real window. Later, when the data is ready, you can create the real document window controller, and use 'addWindowController' to inform your document object.


In other words, to solve this problem properly, you're going to have to handle the necessary background activity with more sophistication, and go into the document architecture a bit more deeply. This isn't easy, but it's not so difficult to prevent you from solving it.

Accepted Answer

Well, readFromURL is either called on the main thread or it isn't. If it isn't, it can't do things like showing windows, since UI-related stuff has to be done on the main thread. If it is on the main thread, then it's going to be blocking the main thread, so UI updates may be delayed in their effect until the blockage is cleared. Either way, you're in trouble, and there's no predicting what the user might see. (In particular, the fact that it used to seem to work OK doesn't demonstrate that your approach was correct.)


If you want to solve this properly, you should probably start by moving your mutli-second calculations to a background thread, either using NSOperation or GCD. Yes, that means if you do nothing else, your document window will open before the data is available. So, step 2, you must either design your window so that it's blank or shows a placeholder until the data is ready, or you must delay the opening of that window until the data is ready.


For the latter, you can override NSDocument's 'makeWindowControllers' method (which is called on the main thread). Perhaps in there you can test whether the data is ready, and if not open a progress panel instead of the real window. Later, when the data is ready, you can create the real document window controller, and use 'addWindowController' to inform your document object.


In other words, to solve this problem properly, you're going to have to handle the necessary background activity with more sophistication, and go into the document architecture a bit more deeply. This isn't easy, but it's not so difficult to prevent you from solving it.

Thank you very much! I was afraid I’d have to do something like that. Your detailed answer is very helpful, as I am not a professional programmer.

showWindow: shows window too late
 
 
Q