Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Swift wrapper for Grand Central Dispatch (GCD)
//
// dispatch.swift
//
// Created by Adam Wróbel. Read more at:
// http://adamwrobel.com/blog/2016/05/08/swift-gcd-wrapper/
//
import Foundation
internal extension dispatch_queue_t {
/// Submits a block for asynchronous execution on this queue and returns
/// immediately.
final func async(block: dispatch_block_t) {
dispatch_async(self, block)
}
/// Submits a block for asynchronous execution on this queue and associates
/// the block with given group.
final func async(group: dispatch_group_t, block: dispatch_block_t) {
dispatch_group_async(group, self, block)
}
/// Submits a block object for execution on this queue and waits until that
/// block completes.
///
/// Calling this method on the current queue results in deadlock.
final func sync(block: dispatch_block_t) {
dispatch_sync(self, block)
}
/// Submits a block object for execution on this queue and waits until that
/// block completes.
///
/// Prevents deadlock by executing the block immediately if called on the
/// current queue. Performing this safety check adds a little overhead when
/// compared with `sync`.
final func safeSync(block: dispatch_block_t) {
isCurrent() ? block() : sync(block)
}
/// Enqueue a block for execution after specified number of seconds.
final func after(seconds: Double, block: dispatch_block_t) {
let when = dispatch_time(DISPATCH_TIME_NOW, Int64(seconds * 1_000_000_000))
dispatch_after(when, self, block)
}
/// Asynchronously runs a block on this queue when the group's tasks are
/// complete.
final func after(group: dispatch_group_t, block: dispatch_block_t) {
group.notify(self, block: block)
}
}
internal extension dispatch_group_t {
/// Waits until all of the group's tasks are complete.
final func wait() {
dispatch_group_wait(self, DISPATCH_TIME_FOREVER)
}
/// Asynchronously runs a block on the main queue when the group's tasks are
/// complete.
final func notify(block: dispatch_block_t) {
dispatch_group_notify(self, dispatch.main, block)
}
/// Asynchronously runs a block on the given queue when the group's tasks are
/// complete.
final func notify(queue: dispatch_queue_t, block: dispatch_block_t) {
dispatch_group_notify(self, queue, block)
}
}
final internal class dispatch {
/// Serial queue associated with the application’s main thread.
class var main: dispatch_queue_t {
return dispatch_get_main_queue()
}
/// Parallel queue used for work that is not user initiated or visible.
class var bg: dispatch_queue_t {
return dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0)
}
/// Parallel queue used for work which the user is unlikely to be immediately
/// waiting for the results.
class var utility: dispatch_queue_t {
return dispatch_get_global_queue(QOS_CLASS_UTILITY, 0)
}
/// Parallel queue used for work that has been explicitly requested by the
/// user, and for which results must be immediately presented in order to
/// allow for further user interaction.
class var user: dispatch_queue_t {
return dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)
}
/// Parallel queue used for work directly involved in providing an
/// interactive UI.
class var interactive: dispatch_queue_t {
return dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0)
}
/// Creates a new group with which block objects can be associated.
class func createGroup() -> dispatch_group_t {
return dispatch_group_create()
}
}
// Private extensions used exclusively to support `safeSync`
private extension dispatch {
static var identityKey = UnsafePointer<Int8>(bitPattern: 1234)
class var currentIdentity: UnsafeMutablePointer<Void> {
return dispatch_get_specific(identityKey)
}
}
private extension dispatch_queue_t {
/// Uses queue specific context to determine if we're executing on this queue.
func isCurrent() -> Bool {
var ourIdentity = identity
if ourIdentity == nil {
ourIdentity = UnsafeMutablePointer<Void>(label)
dispatch_queue_set_specific(self, dispatch.identityKey, ourIdentity, nil)
}
return ourIdentity == dispatch.currentIdentity
}
var label: UnsafePointer<Int8> {
return dispatch_queue_get_label(self)
}
var identity: UnsafeMutablePointer<Void> {
return dispatch_queue_get_specific(self, dispatch.identityKey)
}
}
// this will wait for completion and will deadlock when called from main queue
dispatch.interactive.sync {
print("hello from main queue")
}
// this will return immediately
dispatch.utility.async {
print("working with the Utility QoS")
}
// a safe sync operation that can be sent from any queue to any queue
dispatch.main.safeSync {
print("safety in mind")
}
// this schedules a delayed block
dispatch.main.after(2.5) {
printWithTime("hello from main after 2.5 seconds")
}
let group = dispatch.createGroup()
// schedule some asynchronous tasks
dispatch.interactive.async(group) {
print("part of the job")
}
dispatch.user.async(group) {
print("another part of the job")
}
// schedule asynchronous finalizer
group.notify {
print("this will be executed when all of the group tasks complete")
}
// or synchronously wait for the group to complete
group.wait()
print("group completed")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.