#swift #closures
#swift #замыкания
Вопрос:
Я писал некоторый код, похожий на:
class ViewController : UIViewController {
var foo = "foo"
override func viewDidLoad() {
let alert = UIAlertController(title: "", message: "", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "", style: .default, handler: { _ in
print(foo)
}))
}
}
Xcode сообщает об ошибке, print(foo)
которую я забыл зафиксировать self
, и предлагает два исправления.:
-
print(self.foo)
, или; -
Добавьте список захвата
[self]
к замыканию:... handler: { [self] _ in ...
Теперь я помню, что до Xcode 12 / Swift 5.3 он не использовался для этого. Это либо не дает исправлений, либо только первое.
Мой вопрос в том, в чем разница между этими двумя исправлениями? Они каким-то образом захватывают self
по-другому?
Руководство по языку, похоже, немного затрагивает это, но, похоже, не говорит, в чем разница между ними.
Комментарии:
1. Просто прочитав из руководства по языку: «Вот версия doSomething(), которая захватывает self, включая его в список захвата замыкания, а затем неявно ссылается на self» (в отличие от 1 или 2 предложений перед ним) — подразумевает, что захват
[self]
позволяет записать экранирующее замыкание, ссылающееся наself неявно повсюду (против необходимости писать его явно). Итак, похоже, это вопрос предпочтений2. Просто для справки, это новая функция, реализованная в Swift v5.3: SE-0269 — Повышение доступности implicit
self
в@escaping
замыканиях, когда ссылочные циклы маловероятны
Ответ №1:
Эти два функционально одинаковы, оба явно захватывают self
. [self]
Шаблон позволяет избежать необходимости засорять замыкание повторяющимися self.
ссылками, если у вас было несколько ссылок на свойства и / или методы. Но они оба делают в точности одно и то же — захватывают self
.
Как говорится в документе, на который вы ссылаетесь:
Обычно замыкание захватывает переменные неявно, используя их в теле замыкания, но в этом случае вам нужно быть явным. Если вы хотите захватить
self
, напишитеself
явно, когда вы его используете, или включитеself
в список захвата закрытия.
Суть в том, что это одно и то же.
Как бы то ни было, другой вариант — self
вообще избегать захвата. Например, вы можете только захватывать foo
:
alert.addAction(UIAlertAction(title: "", style: .default) { [foo] _ in
print(foo)
})