Spinning artillery mac os. I've been working on a Mac app lately, and while some things are similar to iOS, something are definitely different. One thing that is different are modal windows and run loops.
PKard® for Mac replaces the native macOS public key infrastructure (PKI) solution to provide you with a solid product with full, U.S.-based support bundled at no additional cost. It's the same commercial code used by the Pentagon, all six Department of Defense (DoD) services, the White House, NIH, and DOI across tens of thousands of Mac. In Kerbal Space Program, take charge of the space program for the alien race known as the Kerbals. You have access to an array of parts to assemble fully-functional spacecraft that flies (or doesn't) based on realistic aerodynamic and orbital physics. There are emulators for different platforms like Windows, Android, iOS and Mac OS X. The ROM contains the video game files of Kirby's Dream Course and the emulator acts as the game console. To be able to play you must introduce the downloaded ROM in the folder of your emulator.
When you display a modal view on iOS you don't get a new run loop for the view, but when you display a modal window on OS X a new run loop is created for the window. This is not necessarily a big deal unless you have a habit of using GCD to dispatch work between background and main queues. Let me give a more specific example.
I display a modal view, or in the cause of OS X, a modal window. The current view is managed by a view controller. User input is captured, then a URL request is sent off to a server on the Internet. The view controller is then notified when the URL request completes.
The typical pattern I follow for sending the request to the server and getting notified when done is to call a method that will dispatch the URL request to a background queue then dispatch to the main queue to call a block when complete. It looks something like this:
This is a simplified view of the pattern I often use. Call a method with a callback block. Perform some work on a background thread. When done, call the callback block on the main thread.
This pattern has served me well on iOS, but it has issues on Mac OS X when displaying a modal window.
When you display a modal window with +[NSApp runModalForWindow:]
a new run loop is created for the window1. That might seem fine until you call dispatch_async(dispatch_get_main_queue(), ^{})
from a background thread. The block that you are trying to execute in the main queue will never run. And in my case, the completion
block is never called. This means my modal window never receives the notification that the URL request completed. (NOTE: Mike Ash pointed out that it's not the new run loop that causes the problem.)
Spinning artillery mac os. I've been working on a Mac app lately, and while some things are similar to iOS, something are definitely different. One thing that is different are modal windows and run loops.
PKard® for Mac replaces the native macOS public key infrastructure (PKI) solution to provide you with a solid product with full, U.S.-based support bundled at no additional cost. It's the same commercial code used by the Pentagon, all six Department of Defense (DoD) services, the White House, NIH, and DOI across tens of thousands of Mac. In Kerbal Space Program, take charge of the space program for the alien race known as the Kerbals. You have access to an array of parts to assemble fully-functional spacecraft that flies (or doesn't) based on realistic aerodynamic and orbital physics. There are emulators for different platforms like Windows, Android, iOS and Mac OS X. The ROM contains the video game files of Kirby's Dream Course and the emulator acts as the game console. To be able to play you must introduce the downloaded ROM in the folder of your emulator.
When you display a modal view on iOS you don't get a new run loop for the view, but when you display a modal window on OS X a new run loop is created for the window. This is not necessarily a big deal unless you have a habit of using GCD to dispatch work between background and main queues. Let me give a more specific example.
I display a modal view, or in the cause of OS X, a modal window. The current view is managed by a view controller. User input is captured, then a URL request is sent off to a server on the Internet. The view controller is then notified when the URL request completes.
The typical pattern I follow for sending the request to the server and getting notified when done is to call a method that will dispatch the URL request to a background queue then dispatch to the main queue to call a block when complete. It looks something like this:
This is a simplified view of the pattern I often use. Call a method with a callback block. Perform some work on a background thread. When done, call the callback block on the main thread.
This pattern has served me well on iOS, but it has issues on Mac OS X when displaying a modal window.
When you display a modal window with +[NSApp runModalForWindow:]
a new run loop is created for the window1. That might seem fine until you call dispatch_async(dispatch_get_main_queue(), ^{})
from a background thread. The block that you are trying to execute in the main queue will never run. And in my case, the completion
block is never called. This means my modal window never receives the notification that the URL request completed. (NOTE: Mike Ash pointed out that it's not the new run loop that causes the problem.)
Klurby Mac Os 11
So how did I work around this problem?
Instead of dispatching the completion()
to the main queue, I call it directly from the background thread. In the completion block itself, I decide how to get the code should run in the main thread. If my window isn't modal, then I can use dispatch_async(dispatch_get_main_queue(), ^{})
. But if my window is modal, which just happens to be the case for the app I'm working on, then I use -performSelectorOnMainThread:withObject:waitUntilDone:
. So the code in my view controller looks something like this:
This pattern change now has me re-thinking how I use certain patterns in my code, especially for code that I intend on sharing between the two platforms.
Update: I posted a sample project that illustrates the problem. In writing the sample app, I learned that the scenario that causes the problem is when the modal window is presented via a block that is dispatched asynchronously on the main queue.
Update 2: Mike Ash pointed out that NSRunLoop is reentrant but GCD serial queues are not and this is the reason, not my theory of a different event loop, the block isn't executed. Mike said, 'The main queue is already executing a block, and it won't execute a new one until that one is done. This is a subtle way in which dispatch on the main queue isn't the same as performSelectorOnMainThread
.'
Good to know and thanks, Mike, for explaining what is happening. Flappy bird (itch) (arpan neupane) mac os.
From the Apple documentation for
+[NSApp runModalForWindow:]
: 'This method runs a modal event loop for the specified window synchronously. It displays the specified window, makes it key, starts the run loop, and processes events for that window. (You do not need to show the window yourself.) While the app is in that loop, it does not respond to any other events (including mouse, keyboard, or window-close events) unless they are associated with the window. It also does not perform any tasks (such as firing timers) that are not associated with the modal run loop. In other words, this method consumes only enough CPU time to process events and dispatch them to the action methods associated with the modal window.' ↩
Kirby Mac Os Catalina
Posted in programming. Tagged in objective-c, os x.