Skip to content

Instantly share code, notes, and snippets.

@antoniocasero
Last active April 28, 2017 14:56
Show Gist options
  • Select an option

  • Save antoniocasero/61d20786310d1398eb254f79bdd142d2 to your computer and use it in GitHub Desktop.

Select an option

Save antoniocasero/61d20786310d1398eb254f79bdd142d2 to your computer and use it in GitHub Desktop.
Async Chainable
// Created by Palmero, Antonio on 04/01/2017.
// Copyright © 2017 ACP. All rights reserved.
//
import Foundation
public typealias ResultOp = Start
public typealias OperationClosure = ((ResultOp) -> Void)
public typealias ErrorClosure = ((Error) -> Void)
public class Start {
@discardableResult
public static func async(name: String? = nil, on queue: DispatchQueue = .main, result this: @escaping OperationClosure) -> Start {
let first = Start(name: name, on: queue, index: 0, do: this)
queue.async {
first.start(first)
}
return first
}
public private(set) var name: String?
public private(set) var index: Int
fileprivate var onQueue: DispatchQueue = .main
fileprivate var start: OperationClosure
public fileprivate(set) var error: Error?
public fileprivate(set) var previousResult: Any?
fileprivate var next: Start?
fileprivate var catchOpertion: ErrorClosure?
fileprivate var finallyOperation: OperationClosure?
fileprivate init(name: String?, on queue: DispatchQueue, index: Int, do result: @escaping OperationClosure) {
self.name = name
self.index = index
self.onQueue = queue
self.start = result
}
private var lastOperation: Start {
var last = self
while let next = last.next {
last = next
}
return last
}
public func done(result: Any? = nil, error: Error? = nil) {
//Error case
if let error = error {
self.error = error
lastOperation.catchOpertion?(error)
lastOperation.previousResult = result
lastOperation.finallyOperation?(lastOperation)
return
}
//End of operation chain
guard let next = self.next else {
lastOperation.previousResult = result
lastOperation.finallyOperation?(lastOperation)
return
}
//Next operation chain.
next.onQueue.async {
next.previousResult = result
next.start(next)
}
}
public func then(name: String? = nil, on queue: DispatchQueue? = nil, do this: @escaping OperationClosure) -> Start {
guard self.catchOpertion == nil else {
fatalError("Can't call then() after catch()")
}
let queue = queue ?? self.onQueue
let next = Start(name: name, on: queue, index: self.index + 1, do: this)
self.next = next
return next
}
@discardableResult
public func `catch`(this: @escaping ErrorClosure) -> Start {
self.catchOpertion = this
return self
}
public func finally(this: @escaping OperationClosure) {
self.finallyOperation = this
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment