Last active
November 4, 2016 22:58
-
-
Save amw/9d62f247d0de3fa08e5facc59bc91037 to your computer and use it in GitHub Desktop.
Swift wrapper for Grand Central Dispatch (GCD)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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 file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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") | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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