To run the example project, clone the repo, and run pod install from the Example directory first.
Spindle is available through CocoaPods. To install it, simply add the following line to your Podfile:
pod'Spindle'The Spindle library is relatively light weight, so one option is to copy the IdentifiableDispatchQueue file into your project or workspace.
The IdentifiableDispatchQueue mimics the initializers of DispatchQueue to make replacing as easy as possible.
Serial Queue
letserialQueue=IdentifiableDispatchQueue(label:"com.app.serial.queue")Concurrent Queue
letconcurrentQueue=IdentifiableDispatchQueue(label:"com.app.concurrent.queue", attributes:[.concurrent])with Quality of Service (qos)
letconcurrentQueue=IdentifiableDispatchQueue(label:"com.app.concurrent.queue", qos:.background, attributes:[.concurrent])Init with underlying queue (failable initializer)
letsomeQueue=DispatchQueue(label:"com.app.some.queue")letidentifiableQueue:IdentifiableDispatchQueue?=IdentifiableDispatchQueue(underlyingQueue: someQueue)Deadlock prevention
letwriteQueue=IdentifiableDispatchQueue(label:"com.app.database-write.queue")
// synchronously write to the database
func write(obj:DBObject){ifIdentifiableDispatchQueue.currentQueueIs(writeQueue){save(obj)}else{
writeQueue.queue.sync{save(obj)}}}privatefunc save(obj:DBObject){
// save
}Queue Assertion
letcommandQueue=IdentifiableDispatchQueue(label:"com.app.command-processing.queue")func updateCache(obj:SomeObject){
commandQueue.queue.async{emptyOutdated()fillCache(obj)}}privatefunc emptyOutdated(){precondition(IDQ.currentQueueIs(commandQueue),"This method should only be called on the commandQueue")}privatefunc fillCache(obj:SomeObject){precondition(IDQ.currentQueueIs(commandQueue),"This method should only be called on the commandQueue")}Debugging
In a situation where threading is heavily used, sometimes it's helpful to be able to tell which queues are causing conflicts or performing stateful mutations.
The only caveat is that you cannot use a default global queues as the underlying queue as all concurrent queues ultimately retarget the global queue with the corresponding Quality of Service (qos). This means that if global queues were allowed to be used as underlying queues, they would cause false positives when passed into the currentQueueIs function during execution on a concurrent queue with the same qos.
If you require a queue with a specific qos, simply pass the qos into the IdentifiableDispatchQueue's initializer.
Spindle is available under the MIT license. See the LICENSE file for more info.