Sajjon
(Alexander Cyon)
1
When we use the weak modifier before either self or some property (reference type, not struct) of self in a capture list we create a new local variable having the same name as the captured type but being weak. This is a bit odd. The resulting code is really confusing if you want to use good variables names. Have a look at the code in RxSwift extenison doing the weakify, strongify dance:
func weakify<A: AnyObject, B>(_ obj: A, method: ((A) -> (B) -> Void)?) -> ((B) -> Void) {
return { [weak obj] value in
guard let obj = obj else { return }
method?(obj)(value)
}
}
The naming of the object is just obj, which is not so swifty. When we attempt to replace obj more descriptive names we see that it easily gets MORE confusing:
func weakify<A: AnyObject, B>(_ strongObject: A, method: ((A) -> (B) -> Void)?) -> ((B) -> Void) {
return { [weak strongObject] value in // strongObject is actually now weak, thanks to the `weak` in the capture list
let weakObject: A? = strongObject // correcting the confusing name `strongObject`, which actually is weak
guard let strongAgain = weakObject else { return } // we have now strongified the weakified initial object
method?(strongAgain)(value)
}
}
If we could weakify and also rename the captured type as an action we could get more easily read code:
func weakify<A: AnyObject, B>(_ strongObject: A, method: ((A) -> (B) -> Void)?) -> ((B) -> Void) {
return { [weak strongObject -> weakObject] value in
guard let object = weakObject else { return }
method?(object)(value)
}
}
What do you say?
Jon_Shier
(Jon Shier)
2
Better solution would just be to automate the unwrapping inside the closure or weak capture in general. But until that's available, I think shadowing is the Swifty solution. If you don't like obj as a name, give it a better name (which weak/strongObject certainly is not).
func weakify<A: AnyObject, B>(_ reference: A, method: ((A) -> (B) -> Void)?) -> ((B) -> Void) {
return { [weak reference] value in
guard let reference = reference else { return }
method?(reference)(value)
}
}
1 Like
func weakify<A: AnyObject, B>(_ strongObject: A, method: ((A) -> (B) -> Void)?) -> ((B) -> Void) {
return { [weak weakObject = strongObject] value in
guard let object = weakObject else { return }
method?(object)(value)
}
}
4 Likes
Joe_Groff
(Joe Groff)
4
You can already do this:
class C {}
var x = C()
let closure = {[weak y = x] in print(y) }
closure() // should print Optional(foo.C)
x = C()
closure() // should print nil
5 Likes
Sajjon
(Alexander Cyon)
5
Oh I have missed that completely, nice @linqingmo @Joe_Groff ! I found it in the swift docs now:
https://docs.swift.org/swift-book/ReferenceManual/Expressions.html
// Weak capture of "self.parent" as "parent"
myFunction { [weak parent = self.parent] in print(parent!.title) }