Skip to content

Instantly share code, notes, and snippets.

@jmcd
Last active June 6, 2018 05:36
Show Gist options
  • Save jmcd/7d672b1238eb5d83785a1075b17cb6f7 to your computer and use it in GitHub Desktop.
Save jmcd/7d672b1238eb5d83785a1075b17cb6f7 to your computer and use it in GitHub Desktop.
Chaining async calls in Swift
struct AsyncTaskChain<Success, Error> {
typealias TaskClosure = (Success?, Error?) -> ()
typealias Task = (TaskClosure) -> ()
typealias ChainClosure = ([Success], Error?)->()
private let tasks: [Task]
private let completion: ChainClosure
private let previousSuccesses: [Success]
init(linkingTasks tasks: [Task], completion: @escaping ChainClosure) {
self.init(previousSuccesses: [], tasks: tasks, completion: completion)
}
private init(previousSuccesses: [Success], tasks: [Task], completion: @escaping ChainClosure) {
self.previousSuccesses = previousSuccesses
self.tasks = tasks
self.completion = completion
}
func begin() {
guard let task = tasks.first else {
self.completion(previousSuccesses, nil)
return
}
task { (success, error) in
if let success = success {
let successes = previousSuccesses + [success]
let pendingTasks = Array(tasks[1..<tasks.count])
let shortenedChain = AsyncTaskChain(previousSuccesses: successes, tasks: pendingTasks, completion: self.completion)
shortenedChain.begin()
} else {
self.completion(previousSuccesses, error)
}
}
}
}
var chain = AsyncTaskChain(linkingTasks: [ pt0, pt1, pt2 ]) { (successes, error) in
if let error = error {
print("ERROR \(error)")
}
print("successes: \(successes)")
}
chain.begin()
/* prints
successes: ["str0", "str1", "str2"]
*/
var chain = AsyncTaskChain(linkingTasks: [ pt0, pt1_failing, pt2 ]) { (successes, error) in
if let error = error {
print("ERROR \(error)")
}
print("successes: \(successes)")
}
chain.begin()
/* prints
ERROR Generic
successes: ["str0"]
*/
enum Err: Error {
case Generic
}
func pt0(completion: (String?, Error?)->()) {
completion("str0", nil)
}
func pt1(completion: (String?, Error?)->()) {
completion("str1", nil)
}
func pt1_failing(completion: (String?, Error?)->()) {
completion(nil, Err.Generic)
}
func pt2(completion: (String?, Error?)->()) {
completion("str2", nil)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment