Created
February 11, 2019 06:09
-
-
Save kingiol/e54b3f9f89a9c4006a993845d859c68a to your computer and use it in GitHub Desktop.
Task - single task, group tasks, sequence tasks
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
struct Task { | |
enum Result { | |
case success | |
case failure(Error) | |
} | |
struct Controller { | |
fileprivate let queue: DispatchQueue | |
fileprivate let handler: (Result) -> Void | |
func finish() { | |
handler(.success) | |
} | |
func fail(with error: Error) { | |
handler(.failure(error)) | |
} | |
} | |
typealias Closure = (Controller) -> Void | |
private let closure: Closure | |
init(closure: @escaping Closure) { | |
self.closure = closure | |
} | |
func perform(on queue: DispatchQueue = .global(), | |
then handler: @escaping (Result) -> Void) { | |
queue.async { [weak self] in | |
let controller = Controller(queue: queue, handler: handler) | |
self?.closure(controller) | |
} | |
} | |
} | |
// MARK: - Single Task | |
extension Task { | |
static func demoUploadingTask() -> Task { | |
return Task { (controller) in | |
// run uploading data to server | |
// uploader.uploading(data) { error in | |
// if let error = error { | |
// controller.fail(with: error) | |
// } else { | |
controller.finish() | |
// } | |
} | |
} | |
} | |
// MARK: - Group Tasks | |
extension Task { | |
static func group(_ tasks: [Task]) -> Task { | |
return Task { controller in | |
let group = DispatchGroup() | |
var anyError: Error? | |
for task in tasks { | |
group.enter() | |
// It's important to make the sub-tasks execute on the same DispatchQueue as the group, | |
// Since we might cause unexpected threading issue otherwise. | |
task.perform(on: controller.queue, then: { (result) in | |
switch result { | |
case .success: | |
break | |
case .failure(let error): | |
anyError = error | |
} | |
group.leave() | |
}) | |
} | |
group.notify(queue: controller.queue) { | |
if let error = anyError { | |
controller.fail(with: error) | |
} else { | |
controller.finish() | |
} | |
} | |
} | |
} | |
} | |
// MARK: - Sequence Tasks | |
extension Task { | |
static func sequence(_ tasks: [Task]) -> Task { | |
var index = 0 | |
func performNext(using controller: Controller) { | |
guard index < tasks.count else { | |
// We've reached the end of our array of tasks, time to finish the sequence | |
controller.finish() | |
return | |
} | |
let task = tasks[index] | |
index += 1 | |
task.perform(on: controller.queue) { result in | |
switch result { | |
case .success: | |
performNext(using: controller) | |
case .failure(let error): | |
// As soon as an error was occurred, we'll faile the entire sequence. | |
controller.fail(with: error) | |
} | |
} | |
} | |
return Task(closure: performNext) | |
} | |
} | |
// Demo single task | |
let uploadingTask = Task.demoUploadingTask() | |
uploadingTask.perform { (result) in | |
// handle uploading result | |
} | |
// Demo group tasks | |
let uploadintTask1 = Task.demoUploadingTask() | |
let uploadintTask2 = Task.demoUploadingTask() | |
let groupTask = Task.group([uploadintTask1, uploadintTask2]) | |
groupTask.perform { (result) in | |
// handle group task result | |
} | |
// Demo sequence tasks | |
let uploadingTask3 = Task.demoUploadingTask() | |
let uploadingTask4 = Task.demoUploadingTask() | |
let publishPostTask = Task.demoUploadingTask() | |
let sequenceTasks = Task.sequence([Task.group([uploadingTask3, uploadingTask4]), publishPostTask]) | |
sequenceTasks.perform { (result) in | |
// handle sequence task result | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment