Skip to content

Instantly share code, notes, and snippets.

@szotp
Last active June 30, 2019 11:39
Show Gist options
  • Save szotp/84b6e48a2c35cab51783a5c0bc4ca2ef to your computer and use it in GitHub Desktop.
Save szotp/84b6e48a2c35cab51783a5c0bc4ca2ef to your computer and use it in GitHub Desktop.
Handling result with less completion calls
//
// main.swift
// Completions
//
// Created by szotp on 30/06/2019.
// Copyright © 2019 szotp. All rights reserved.
//
import Foundation
typealias CompletionBlock = Optional<() -> Void>
func apiRequest(input: Int, onSuccess: (String) -> Void, onFailure: (Error) -> Void) {
onSuccess("")
}
func apiRequestWrapped(completion: CompletionBlock) {
let cmpl = Completor<String>(completion) { result in
let data = try result.get()
print(data)
}
if (arc4random() % 2) == 0 {
apiRequest(input: 5, onSuccess: cmpl.onSuccess, onFailure: cmpl.onFailure)
} else {
// cmpl.deinit will be called and complete automatically
}
}
class Completor<T> {
typealias ResultCallback = (Result<T, Error>) throws -> Void
private var didComplete = false
private var completion: CompletionBlock
private var onResult: ResultCallback
init(_ completion: CompletionBlock, onResult: @escaping ResultCallback) {
self.completion = completion
self.onResult = onResult
}
func onSuccess(value: T) {
complete(.success(value))
}
func onFailure(error: Error) {
print(error)
complete(.failure(error))
}
func complete(_ result: Result<T, Error>?) {
assert(!didComplete)
if let result = result {
do {
try onResult(result)
} catch let error {
// apply default behavior here, show toast or something, depends on the app
print(error)
}
}
let completion = self.completion
DispatchQueue.main.async {
let desc = result.map { "\($0)"} ?? "nil"
print("completion with \(desc)")
completion?()
}
didComplete = true
}
deinit {
if !didComplete {
complete(nil)
}
}
}
apiRequestWrapped {
print("ok")
}
RunLoop.main.run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment