Allow implicit self for weak self captures, after self is unwrapped
Table of Contents
Swift allows implicit self in many places.
It removes visual noise and allows developers to focus on things that matter.
In Swift 5.8, Swift expands the case, which enables the implicit self to be used within an escaping closure.
self in an escaping closure
When we reference self
in escaping closures, it has the potential to produce strong reference cycles.
So, Swift wants to make us aware of the risk by requiring us to explicitly specify the self
keyword when referencing self
in the closure.
As Swift gets smarter (SE-0268), it allows us to omit the self
keyword in some cases when reference cycles are unlikely to occur. For example, when self is a value type.
In Swift 5.8 (SE-0365), Swift expands the case and allows us to omit self
keyword where a weak self capture has been unwrapped.
You can easily support sarunw.com by checking out this sponsor.
AI Grammar: Correct grammar, spell check, check punctuation, and parphrase.
Allow implicit self for weak self captures, after self is unwrapped
The wording might seem complicated, but it is an improvement on a strongify weakify dance we usually do when using self in an escaping closure.
In brief, we no longer require the self
keyword if:
- Has weak self captured, e.g.,
[weak self]
. - It has been unwrapped, e.g.,
if let
,guard let
.
class ViewController: UIViewController {
var button: UIButton!
func setup() {
button.addAction(
UIAction { [weak self] _ in
guard let self else { return }
didTapButton()
},
for: .touchUpInside)
}
func didTapButton() {}
}
Before Swift 5.8, we need to add the self
keyword when referencing self.didTapButton()
.
Variations
This works for all optional unwrapping techniques as long as you assign weak self to a variable named "self".
All of the following forms are valid.
button.addAction(
UIAction { [weak self] _ in
guard let self else { return }
didTapButton()
},
for: .touchUpInside)
button.addAction(
UIAction { [weak self] _ in
guard let self = self else { return }
didTapButton()
},
for: .touchUpInside)
button.addAction(
UIAction { [weak self] _ in
if let self {
didTapButton()
}
},
for: .touchUpInside)
button.addAction(
UIAction { [weak self] _ in
if let self = self {
didTapButton()
}
},
for: .touchUpInside)
Naming it otherwise won't work.
button.addAction(
UIAction { [weak self] _ in
guard let strongSelf = self else { return }
didTapButton()
// Call to method 'didTapButton' in closure requires explicit use of 'self' to make capture semantics explicit
},
for: .touchUpInside)
You can easily support sarunw.com by checking out this sponsor.
AI Grammar: Correct grammar, spell check, check punctuation, and parphrase.
Summary
self
keyword in escaping closures help us aware of a strong reference cycles.
Since the self has already been captured explicitly ([weak self]
) and explicitly unwrapped, there is limited value in requiring us to use the self keyword.
Callers are fully aware of it at this point.
This new feature removes visual noise from the body of closures using weak self-captures.
Read more article about Swift, Swift 5.8, or see all available topic
Enjoy the read?
If you enjoy this article, you can subscribe to the weekly newsletter.
Every Friday, you'll get a quick recap of all articles and tips posted on this site. No strings attached. Unsubscribe anytime.
Feel free to follow me on Twitter and ask your questions related to this post. Thanks for reading and see you next time.
If you enjoy my writing, please check out my Patreon https://www.patreon.com/sarunw and become my supporter. Sharing the article is also greatly appreciated.
Become a patron Buy me a coffee Tweet ShareBack deploy Swift Function
Does this mean we can finally enjoy the new SwiftUI feature while still supporting old versions of iOS? Let's find out.
How to Disable swipe down to dismiss Sheet in SwiftUI
By default, you can dismiss a sheet presentation using a swipe-down gesture. But you might don't want this behavior on every sheet. Learn how to disable it in SwiftUI.