Dealing With Weak in Closure-based Delegation
Oleg Dreyman (via Joshua Emmons):
Let’s look at the core of the problem: 99% of the time, when assigning a delegation callback, there should be a
[weak self]
capture list, but nothing is actually preventing ourselves from omitting it. No errors, no warnings, nothing. What if instead we could force the correct behavior?[…]
Leveraging the power of Swift generics, we can do better:
struct DelegatedCall<Input> { private(set) var callback: ((Input) -> Void)? mutating func delegate<Object : AnyObject>(to object: Object, with callback: @escaping (Object, Input) -> Void) { self.callback = { [weak object] input in guard let object = object else { return } callback(object, input) } } }
2 Comments RSS · Twitter
Dreyman's general thesis is solid:
Previously [in the classic Cocoa delegate pattern], the designer of an ImageDownloader API was responsible for not introducing any memory leaks to our app. Now [with closure-based delegation], it’s an exclusive obligation of the API user.
However, I disagree with his taste that this kind of declaration
init() { downloader.didDownload.delegate(to: self) { (self, image) in self.image = image } }
is more developer-friendly than the original
init() { downloader.didDownload = { [weak self] image in self.image = image } }
Despite my distaste for Swift's disorganized “junk after the opening brace” closure syntax, the capture list still seems a bit cleaner compared to the extra method call and shadowing of `self` as an additional parameter.