На сессии WWDC 2014 403 Intermediate Swift и стенограмма был следующий слайд
В этом случае оратор сказал, что если мы не будем [unowned self]
там пользоваться, это приведет к утечке памяти. Означает ли это, что мы всегда должны использовать [unowned self]
внутри закрытия?
В строке 64 файла ViewController.swift приложения Swift Weather я не пользуюсь [unowned self]
. Но я обновляю пользовательский интерфейс, используя некоторые @IBOutlet
s self.temperature
и self.loadingIndicator
. Это может быть хорошо, потому что все, что @IBOutlet
я определил weak
. Но для безопасности, мы всегда должны использовать [unowned self]
?
class TempNotifier {
var onChange: (Int) -> Void = {_ in }
var currentTemp = 72
init() {
onChange = { [unowned self] temp in
self.currentTemp = temp
}
}
}
swift
automatic-ref-counting
Джейк Лин
источник
источник
onChange
должен быть[weak self]
закрытием, так как это открытое (внутренне, но все же) свойство, поэтому другой объект может получить и сохранить закрытие, сохраняя объект TempNotifier вокруг (неопределенно, если использующий объект не отпустилonChange
замыкание, пока не увидит, чтоTempNotifier
оно ушло, через свою собственную слабую ссылку наTempNotifier
) . Если быvar onChange …
былоprivate var onChange …
то[unowned self]
было бы правильно. Я не уверен на 100% в этом; кто-нибудь поправьте меня, пожалуйста, если я ошибаюсь.[]
? Я не могу найти объяснение в документации Apple.{}
является пустым замыканием (экземпляром замыкания) по умолчанию (ничего не делает),(Int) -> Void
является определением замыкания.Ответы:
Нет, бывают моменты, когда вы бы не хотели использовать
[unowned self]
. Иногда вы хотите, чтобы замыкание захватывало себя, чтобы быть уверенным, что оно все еще существует к моменту вызова замыкания.Пример: создание асинхронного сетевого запроса
Если вы делаете асинхронный сетевой запрос, вы хотите, чтобы закрытие сохранялось
self
до завершения запроса. Этот объект мог быть иначе освобожден, но вы все еще хотите иметь возможность обрабатывать завершение запроса.Когда использовать
unowned self
илиweak self
Единственный раз, когда вы действительно хотите использовать
[unowned self]
или[weak self]
когда вы создадите сильный референсный цикл . Сильный референсный цикл - это когда существует цикл владения, когда объекты в конечном итоге становятся собственниками друг друга (возможно, через третьих лиц), и поэтому они никогда не будут освобождены, поскольку они оба гарантируют, что друг друга останутся.В конкретном случае замыкания вам просто нужно понять, что любая переменная, на которую есть ссылка внутри него, становится «принадлежащей» замыканию. Пока закрытие вокруг, эти объекты гарантированно будут вокруг. Единственный способ остановить это владение - это сделать
[unowned self]
или[weak self]
. Таким образом, если классу принадлежит замыкание, и это замыкание фиксирует сильную ссылку на этот класс, то у вас есть надежный ссылочный цикл между замыканием и классом. Это также включает в себя, если класс владеет чем-то, что владеет замыканием.Конкретно в примере из видео
В примере на слайде
TempNotifier
владеет замыканием черезonChange
переменную-член. Если бы они не объявилиself
какunowned
, закрытие также привело бы кself
созданию сильного ссылочного цикла.Разница между
unowned
иweak
Разница между
unowned
иweak
заключается в том, чтоweak
объявлено как необязательное, аunowned
нет. Объявляя его,weak
вы получаете возможность обрабатывать случай, когда в какой-то момент он может быть нулем внутри замыкания. Если вы попытаетесь получить доступ кunowned
переменной с нулевым значением, это приведет к сбою всей программы. Так что используйте толькоunowned
тогда, когда вы уверены, что переменная всегда будет рядом, пока закрытие вокругисточник
[weak self]
в асинхронном сетевом запросе находится в контроллере представления, где этот запрос используется для заполнения представления. Если пользователь отступает, нам больше не нужно заполнять представление, а также нам не нужна ссылка на контроллер представления.weak
ссылки также устанавливаются,nil
когда объект освобождается.unowned
ссылки не являются.unowned
используются для некоторогоnon-Optional
времениweak
используются дляOptional
так нашегоself
этоOptional
илиnon-optional
?Обновление 11/2016
Я написал статью об этом, расширяя этот ответ (изучая SIL, чтобы понять, что делает ARC), посмотрите здесь .
Оригинальный ответ
Предыдущие ответы не дают простых правил о том, когда использовать один над другим и почему, поэтому позвольте мне добавить несколько вещей.
Неизвестное или слабое обсуждение сводится к вопросу о времени жизни переменной и замыкании, которое на нее ссылается.
Сценарии
У вас может быть два возможных сценария:
Закрытие имеет одинаковое время жизни переменной, поэтому замыкание будет достижимо только до тех пор, пока переменная не будет достигнута . Переменная и замыкание имеют одинаковое время жизни. В этом случае вы должны объявить ссылку как бесхозные . Распространенным примером является
[unowned self]
использование во многих примерах небольших замыканий, которые что-то делают в контексте своего родителя и на которые не ссылаются нигде, не переживают своих родителей.Время жизни закрытия не зависит от значения переменной, на закрытие можно ссылаться, когда переменная больше недоступна. В этом случае вы должны объявить ссылку слабой и убедиться, что она не равна нулю, прежде чем использовать ее (не принудительно распаковывать). Типичным примером этого является то, что
[weak delegate]
вы можете видеть в некоторых примерах замыкания, ссылающегося на совершенно не связанный (по времени жизни) объект делегата.Фактическое использование
Итак, что вы будете / должны использовать в большинстве случаев?
Цитирую Джо Гроффа из твиттера :
Вы найдете больше информации о незнакомой
*
внутренней работе здесь .*
Обычно также упоминается как неизвестный (безопасный), чтобы указать, что проверки во время выполнения (которые приводят к сбою для недействительных ссылок) выполняются перед доступом к неизвестной ссылке.источник
Я думал, что добавлю несколько конкретных примеров специально для контроллера представления. Многие из объяснений, не только здесь, о переполнении стека, действительно хороши, но я лучше работаю с примерами из реального мира (@drewag хорошо с этим справился):
weak
, потому что они долго живут. Контроллер представления может закрыться до завершения запроса, поэтому онself
больше не указывает на действительный объект при вызове замыкания.Если у вас есть замыкание, которое обрабатывает событие на кнопке. Это может быть
unowned
потому, что как только контроллер представления исчезает, кнопка и любые другие элементы, на которые он может ссылаться,self
одновременно исчезают. Закрывающий блок также исчезнет одновременно.источник
weak
а неunowned
правильно?Если « я» может быть нулем в закрытии, используйте « слабое я» .
Если self никогда не будет нулевым в закрытии, используйте [unowned self] .
В документации Apple Swift есть большой раздел с изображениями, объясняющими разницу между использованием сильных , слабых и неиспользуемых замыканий:
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html
источник
Вот блестящие цитаты из форумов разработчиков Apple, описанные вкусные детали:
unowned
противunowned(safe)
противunowned(unsafe)
unowned
противweak
Обновление: в современном Swift
weak
внутренне используется тот же механизм, чтоunowned
и у . Так что это сравнение неверно, потому что сравнивает Objective-Cweak
со Swiftunonwed
.Причины
В восторге?
источник
Здесь есть несколько отличных ответов. Но недавние изменения в том, как Swift реализует слабые ссылки, должны изменить слабую личность каждого против решения о неиспользованном самопользовании. Раньше, если вам требовалась лучшая производительность, использование непризнанного «я» превосходило слабое «Я», если вы были уверены, что «я» никогда не будет равным нулю, потому что доступ к «неизвестному» я гораздо быстрее, чем доступ к «слабому».
Но Майк Эш задокументировал, как Swift обновил реализацию слабых переменных для использования дополнительных таблиц и как это существенно улучшает слабую собственную производительность.
https://mikeash.com/pyblog/friday-qa-2017-09-22-swift-4-weak-references.html
Теперь, когда нет слабого ухудшения производительности, я считаю, что мы должны использовать его в будущем. Преимущество слабого «я» заключается в том, что он является необязательным, что значительно облегчает написание более правильного кода, поэтому в основном Swift является таким замечательным языком. Вы можете подумать, что знаете, какие ситуации безопасны для использования неизвестного «я», но мой опыт анализа большого количества кода других разработчиков, большинство этого не делают. Я исправил множество сбоев, когда unowned self был освобожден, обычно в ситуациях, когда фоновый поток завершается после освобождения контроллера.
Ошибки и сбои - самая трудоемкая, болезненная и дорогая часть программирования. Делайте все возможное, чтобы написать правильный код и избегать их. Я рекомендую сделать это правилом, чтобы никогда не использовать принудительное развертывание необязательных опций и никогда не использовать неподдерживаемое «я» вместо слабого «я». Вы не потеряете ничего, не упустив временную развёртку, и непричастное «я» на самом деле в безопасности. Но вы многое выиграете от устранения труднодоступных и отлаженных сбоев и ошибок.
источник
weak
нельзя использовать вместоunowned
?По словам Apple-док
Пример -
источник
Если ничего из вышеперечисленного не имеет смысла:
ТЛ; др
Объяснение:
Ниже я нашел следующее: слабая ссылка без ссылки . Исходя из того, что я понял, непризнанное «я» не может быть нулевым, но слабое «я» может быть, а непризнанное «я» может привести к висящим указателям ... что-то позорное в Objective-C. Надеюсь, поможет
Неизвестные ссылки, такие как слабые ссылки, не увеличивают количество сохраняемых объектов, на которые ссылаются. Тем не менее, в Swift, неподтвержденная ссылка имеет дополнительное преимущество - она не является дополнительной . Это облегчает управление ими, а не использование дополнительной привязки. Это мало чем отличается от неявно развернутых опций. Кроме того, неизвестные ссылки не обнуляются . Это означает, что когда объект освобождается, он не обнуляет указатель. Это означает, что использование неизвестных ссылок может в некоторых случаях приводить к зависанию указателей., Для вас, ботаников, которые помнят дни Objective-C, как и я, неподтвержденные ссылки отображаются на unsafe_unretained.
Это где это немного сбивает с толку.
Они оба могут быть использованы для прерывания сохранения циклов. Так когда же мы их используем ?!
Согласно документации Apple :
источник
источник