Allow implicit self for weak self captures, after self is unwrapped

⋅ 2 min read ⋅ Swift Swift 5.8

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.

Sponsor sarunw.com and reach thousands of iOS developers.

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:

  1. Has weak self captured, e.g., [weak self].
  2. 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)
Call to method 'didTapButton' in closure requires explicit use of 'self' to make capture semantics explicit.
Call to method 'didTapButton' in closure requires explicit use of 'self' to make capture semantics explicit.

You can easily support sarunw.com by checking out this sponsor.

Sponsor sarunw.com and reach thousands of iOS developers.

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 Share
Previous
Back 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.

Next
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.

← Home