Skip to content

Instantly share code, notes, and snippets.

@samsonjs
Created July 14, 2020 04:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save samsonjs/c398f903b0d5fa66b15ce3ba323f0f83 to your computer and use it in GitHub Desktop.
Save samsonjs/c398f903b0d5fa66b15ce3ba323f0f83 to your computer and use it in GitHub Desktop.
Capture weak references but only call the closure when it hasn't been deallocated
import Foundation
func weakOrBust<A: AnyObject>(_ a: A, _ f: @escaping (A) -> Void) -> () -> Void {
{ [weak a] in
guard let a = a else {
print("object disappeared")
return
}
f(a)
}
}
func weakOrBust<A: AnyObject, B: AnyObject>(_ a: A, _ b: B, _ f: @escaping (A, B) -> Void) -> () -> Void {
{ [weak a, weak b] in
guard let a = a, let b = b else {
print("at least 1 object disappeared")
return
}
f(a ,b)
}
}
func later(f: @escaping () -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1), execute: f)
}
class Monkey {}
var a = Monkey()
later(f: weakOrBust(a) { a in
print("first closure called?! a=\(a)")
})
// Overwrite the first monkey right away causing it to disappear, and the first closure to be skipped.
a = Monkey()
later(f: weakOrBust(a) { a in
print("second closure called a=\(a)")
})
// Everybody wants more monkeys. It's easy to make this work up to a reasonable
// number of arguments, say 3-5. It can go up to 11 if you want but please don't
// want that.
let b = Monkey()
later(f: weakOrBust(a, b) { a, b in
print("third closure called a=\(a) b=\(b)")
})
// vs. the alternative
later(f: { [weak a, weak b] in
guard let a = a, let b = b else { return }
print("fourth closure called a=\(a) b=\(b)")
})
// but on the other hand, you lose trailing closure syntax
later { [weak a, weak b] in
guard let a = a, let b = b else { return }
print("fifth closure called a=\(a) b=\(b)")
}
// sad trombone, this isn't valid syntax
// later weakOrBust(a) { a in
// print("a=\(a)")
// }
// it would be cool to write something like this and have it used as a literal closure,
// including trailing closure syntax
// @weakOrBust { a, b in /* a and b are strong references */ }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment