Having the UI freeze up has been the bane of my Mac programming for years, first using AppleScript Studio, then RubyCocoa. I didn’t even think about trying to multi-thread it until this most recent app exasperated me again, but it seems like massive overkill. “Yes, we’ve got some thinking to do, but when I ask you to update the window, do it, then come back for more thinking!” But calling any and all of the various ‘.display’ options was utterly useless, because Cocoa won’t (or at least, never did for me) update the display until it goes through the event-processing run loop, and it wasn’t doing that until my processing subroutine exited, no matter how much I begged it during the routine to take a little break and update the UI.
I have finally found the secret solution, rather by accident. Certainly nobody (that I could find) ever mentioned this in a forum online, nor did the Apple documentation seem to notice the problem nor provide a solution. Even though I have thought for years that what I wanted to do was tell it “Fine, if you won’t update the screen until you’re back in the run loop, then go do that! Go take a trip through the loop, then come back” I could never find anything that would tell me how. It’s all taken care of for me, you know.
Today, at long last, I have found the secret command to do exactly that: NSRunLoop.currentRunLoop.runMode_beforeDate_(NSDefaultRunLoopMode, nil)
This tells Cocoa to take a single pass through the event loop. I don’t have to call “.displayIfNeeded” or anything else; all the UI items that are connected to outlets or bound to variables or whatnot are updated just like usual.
Because, really, I shouldn’t need threads or forcing a display run (even if it had ever worked for me) for something like
@ reportStatus(“Loading File..”)@
@reportStatus(“Extracting tasty bits…”)@
and so on