Skip to content

Instantly share code, notes, and snippets.

@zacclark
Last active January 15, 2017 05:32
Show Gist options
  • Save zacclark/5ba1d6bed1f38ecb8e21d58529bd50cc to your computer and use it in GitHub Desktop.
Save zacclark/5ba1d6bed1f38ecb8e21d58529bd50cc to your computer and use it in GitHub Desktop.
Lightweight forced completion block calling
struct CompletionBlock {
private let storedBlock: () -> Swift.Void
init(_ c: @escaping () -> Swift.Void) {
storedBlock = c
}
func call() -> Called {
storedBlock()
return Called()
}
struct Called {
fileprivate init() {}
}
}
protocol DataSourceRequestAction {
func start(_ stuff: String, completion: CompletionBlock) -> CompletionBlock.Called
}
class Implementor : DataSourceRequestAction {
func start(_ stuff: String, completion: CompletionBlock) -> CompletionBlock.Called {
guard stuff == "specific thing" else {
print("WRONG")
return completion.call()
}
print("YAY")
return completion.call()
}
}
class SecondOrderImplementor : DataSourceRequestAction {
func start(_ stuff: String, completion: CompletionBlock) -> CompletionBlock.Called {
if stuff == "pass it on" {
return Implementor().start(stuff, completion: completion)
} else {
return completion.call()
}
}
}

I wanted to figure out a way to "force" an implementor to call a completion block before exiting. Because the constructor for a CompletionBlock.Called is fileprivate, the only way for an implementor to "get" one (to satisfy its return type requirement) is to use the call function on the CompletionBlock argument that was passed to it.

If we need to model an addition return value, it wouldn't be too hard to extend CompletionBlock to be generic and accept an argument (or void).

/// The types needed to be un-nested to be generic.
struct CompletionBlock<T> {
private let storedBlock: (T) -> Swift.Void
init(_ c: @escaping (T) -> Swift.Void) {
storedBlock = c
}
func call(_ v: T) -> CalledCompletionBlock<T> {
storedBlock(v)
return CalledCompletionBlock(v)
}
}
struct CalledCompletionBlock<T> {
let value : T
fileprivate init(_ v: T) {
value = v
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment