In Swift, if I have a closure capturing [weak self], is it good practice to unwrap the optional self at the beginning of the closure?
I believe that the first implementation is better because self could become nil between the statements
And that's why the second implementation is in fact better! If self
is not nil at the first statement, the first statement makes it so that self
couldn't become nil
between the statements. It retains self
exactly for the remainder of the block. This is called "the weak–strong dance".
guard let self = self else { return }
// ^^^^ this self is _strong_, not weak; it retains self
Do capture lists of inner closures need to redeclare `self` as `weak` or `unowned`?
The [weak self]
in anotherFunctionWithTrailingClosure
is not needed.
You can empirically test this:
class Experiment {
func someFunctionWithTrailingClosure(closure: @escaping () -> Void) {
print("starting", #function)
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
closure()
print("finishing", #function)
}
}
func anotherFunctionWithTrailingClosure(closure: @escaping () -> Void) {
print("starting", #function)
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
closure()
print("finishing", #function)
}
}
func doSomething() {
print(#function)
}
func testCompletionHandlers() {
someFunctionWithTrailingClosure { [weak self] in
self?.anotherFunctionWithTrailingClosure { // [weak self] in
self?.doSomething()
}
}
}
// go ahead and add `deinit`, so I can see when this is deallocated
deinit {
print("deinit")
}
}
And then:
func performExperiment() {
DispatchQueue.global().async {
let obj = Experiment()
obj.testCompletionHandlers()
// sleep long enough for `anotherFunctionWithTrailingClosure` to start, but not yet call its completion handler
Thread.sleep(forTimeInterval: 1.5)
}
}
If you do this, you will see that doSomething
is never called and that deinit
is called before anotherFunctionWithTrailingClosure
calls its closure.
That having been said, I might still be inclined to use the [weak self]
syntax on anotherFunctionWithTrailingClosure
to make my intent explicit.
Weak reference to closure in Swift
Is it possible to make the closure references weak in my Observable class
No. Only class instances can be referred to via weak references in Swift, and a function is not a class instance. (And not only must they be class instances, they must be an Optional wrapping a class instance.)
There are some pretty obvious ways around this, or course - the simplest being a wrapper class. But I do not actually recommend that in this situation, because you have not convinced me that weak references to functions are needed here in the first place. Remember, a weak reference to an object to which there is no strong reference will instantly lose the reference and will be pointing at nil. I can't believe that is what you want. I think you're barking up a wrong tree here.
Should function arguments be weak?
Weak references aren't something you should use "just because I see a closure".
Even with closures, and even with self
, there are plenty of times where you don't want a weak reference.
Weak references exist to break strong reference cycles. That's it. The captured variables of closures are one kind of strong reference that exists. If a closure strongly captures a variable, nothing scary happens.
The issue is when a closure captures foo
, and then you store the closure inside the foo
. That's a strong reference cycle, which needs to be broken. One of the two references needs to be weak, so either you should hold the closure weakly in the foo
, or you should capture the foo
weakly in the clsoure.
Your persons
has type Array<Person>
. There could be a strong reference cycle if one of those Person
objects has a strong reference to helloView
, which itself has a strong reference to its didHelloPressed
closure. But that would be very weird, and is almost certainly (hopefully!) not what you're doing, so no, there's no need to weakly capture persons
.
Even more, depending on the relationship between helloView
and what self
is in this context, it's entirely possible that you might want to capture self strongly, too.
Related Topics
Expression Resolves to an Unused Function
How to 'Addtarget' to Uilabel in Swift
Custom Mkannotation Not Moving When Coordinate Set
How to Use Nsvisualeffectview to Blend Window with Background
Swift- How to Display Image Over Button
Saving a Codable Struct to Userdefaults with Swift
Trying to Add a Protocol to a Class Signature in Swift
Distributednotificationcenter - How to Pass Data Between Applications
Changing The Color of a Button in Swiftui on Tvos
Partial Application of 'Mutating' Method Is Not Allowed
Swift Change the Tableviewcell Border Color According to Data
Swift Compiler Error Int Is Not Convertible to Cgfloat
How Would I Create a Constant That Could Be One of Several Strings Depending on Conditions
How to Make Function That Some Parameters Not Required in When Call It in iOS Swift 3
Swift Error with Generic Array
Playing Hls (M3U8) in Cocoa Os X Avplayer - Swift
Why Are Objects in the Same Sknode Layer Not Interacting with Each Other