Skip to content

Instantly share code, notes, and snippets.

@loganwright
Created July 22, 2015 20:50
Show Gist options
  • Save loganwright/bbca7784a21120b7a2e9 to your computer and use it in GitHub Desktop.
Save loganwright/bbca7784a21120b7a2e9 to your computer and use it in GitHub Desktop.
Qu

A basic wrapper for dispatch operations in Swift. Syntax example:

    Qu.Background {
        // Sleep for long operation
        sleep(4)
        log("1")
    } .Also {
        sleep(4)
        log("2")
    } .Also {
        sleep(1)
        log("3")
    } .Also {
        sleep(1)
        log("4")
    } .Also {
        sleep(1)
        log("5")
    } .ThenAfter(.Previous(3)) {
        log("6: After 5, 4, & 3")
    } .Then {
        sleep(1)
        log("7: After 6")
    } .FinallyOn(.Main) {
        sleep(1)
        log("Finished: After All")
    }
public typealias Block = () -> ()
// MARK: Qu
public class Qu {
// MARK: Priority Enumeration
public enum Priority {
case Background
case Main
case Custom(NSOperationQueue)
var queue: NSOperationQueue {
switch self {
case .Background:
return NSOperationQueue()
case .Main:
return NSOperationQueue.mainQueue()
case .Custom(let customQueue):
return customQueue
}
}
}
public enum Dependency {
case Last
case All
case Previous(Int)
}
// MARK: Properties
private(set) var priority: Priority
private(set) var operationQueue: NSOperationQueue
/// Completion operation that will attempt to wait for other operations to finish and then execute. If all operations have already executed before this operation is added, it will run immediately. Even if you add operations afterwards.
private(set) var completion: Operation? {
willSet {
if completion != nil && newValue != nil {
print("*** Warning *** Setting multiple completion blocks will result in unpredictable behavior!")
}
}
}
// MARK: Initialization
public required init(priority: Priority) {
self.priority = priority
self.operationQueue = priority.queue
}
// MARK: Class Functions
class func Background(block: Block) -> Self {
let q = self.init(priority: .Background)
return q.Run(block)
}
class func Main(block: Block) -> Self {
let q = self.init(priority: .Main)
return q.Run(block)
}
class func Custom(queue: NSOperationQueue, block: Block) -> Self {
let q = self.init(priority: .Custom(queue))
return q.Run(block)
}
// MARK: Dispatching Functions
func Run(block: Block) -> Self {
return queue(block)
}
func Also(block: Block) -> Self {
return queue(block)
}
func Then(block: Block) -> Self {
return ThenAfter(.Last, block: block)
}
func ThenAfter(dependency: Dependency, block: Block) -> Self {
let blockOp = Operation(block: block)
switch dependency {
case .Last:
if let last = operationQueue.lastOperation {
blockOp.addDependency(last)
}
case .Previous(let previousOperationCount):
let ops = operationQueue.ops
let count = ops.count
let start = count - previousOperationCount
let dependentOperations = ops[start..<count]
for op in dependentOperations {
blockOp.addDependency(op)
}
case .All:
for op in operationQueue.ops {
blockOp.addDependency(op)
}
}
return queue(blockOp)
}
// MARK: Completion
func Finally(block: Block) -> Self {
let op = Operation(block: block)
completion = op
operationQueue.setCompletion(op)
return self
}
func FinallyOn(priority: Priority, block: Block) -> Self {
let wrapped: Block = {
dispatch_async(priority.queue.underlyingQueue, block)
}
return Finally(wrapped)
}
// MARK: Queueing
private func queue(block: Block) -> Self {
return queue(Operation(block: block))
}
private func queue(op: Operation) -> Self {
if let completion = completion {
completion.addDependency(op)
}
operationQueue += op
return self
}
}
// MARK: Operation
class Operation : NSBlockOperation {
private(set) var block: Block!
init(block: Block) {
super.init()
self.block = block
addExecutionBlock(self.block)
}
}
extension Operation {
override var description: String {
return name ?? "[unnamed]"
}
}
// MARK: Operators
func +=(operationQueue: NSOperationQueue, block: Block) {
operationQueue.addOperationWithBlock(block)
}
func +=(operationQueue: NSOperationQueue, operation: NSOperation) {
operationQueue.addOperation(operation)
}
// MARK: NSOperationQueue+Operations
private extension NSOperationQueue {
/// This is the most recently added operation. According to the docs, `operation` is returned in the order they were added to the queue, NOT the order in which they are executed.
var lastOperation: Operation? {
return ops.last
}
var ops: [Operation] {
return operations as? [Operation] ?? []
}
func setCompletion(block: Block) -> Operation {
let blockOp = Operation(block: block)
return setCompletion(blockOp)
}
func setCompletion(blockOp: Operation) -> Operation {
for op in ops {
blockOp.addDependency(op)
}
addOperation(blockOp)
return blockOp
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment