Update 9/12/2018 I’m told dispatch_get_specific
does not work the way
I think it does, and this is not a valid solution. Please do not use this.
Leaving up for posterity.
Original: In my current side-project, I’m writing a swift app that makes liberal use of dispatch queues to move work off the main queue to keep the app responsive. This works great, but there are some Apple APIs (like UIKit) that require calls to be made from the Main thread or Main queue (they are distinct things).
I want to be able to dispatch work to the main queue synchronously, without worrying about whether I’m already running on the main queue or not.
Typically people suggest checking NSThread.isMainThread()
before calling or
dispatching an action, but if the api you’re calling requires the main queue
this may not be enough. You can potentially be running on the main thread,
but not the main queue.
There used to an API to check your current dispatch queue, but that was deprecated with iOS 6. The current strategy appears to be setting a queue specific variable that can only be read from the main queue. This is analogous to thread specific storage (TSS) in in C++ land.
I’ve wrapped this all in an extension to DispatchQueue in Swift 4.1. Now all I
need to do to blindly dispatch synchronous work to the main queue is call
DispatchQueue.dispatchMain { // uikit stuff }
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
The problem with this approach is initializing the queue specific variable.
Right now I have it wrapped in a function called initializeSafeDisptchMain()
that must be called by the application before the first use of
dispatchMain()
. I’d love to find a way to run this automatically on app
startup without having to manaully call it from
application(:didFinishLaunchingWithOptions:)
, but I’m blanking on it right
now. If you can think of a way to do this that isn’t totally gross, please
let me know.