слабый против unowned в Swift. Каковы внутренние различия?
я понимаю, использование и поверхностные различия между weak
и unowned
в Swift:
простейшие примеры я видел, что если есть Dog
и Bone
на Bone
может иметь слабую ссылку на Dog
(и наоборот), потому что каждый может существовать независимо друг от друга.
С другой стороны, в случае Human
и a Heart
на Heart
может быть unowned
ссылка на человека, потому что как только Human
становится... "dereferenced", the Heart
больше не может быть разумно доступен. Это и классический пример с Customer
и CreditCard
.
это не повторяющиеся вопросы об этом.
учитывая, что мы можем просто создать переменную типа такого: weak var customer: Customer!
преимущество unowned
переменные, не являющиеся необязательными-это вопрос спорный.
на только практическое преимущество, которое я вижу в использовании
unowned
vs неявно разворачиваетweak
переменной через!
это мы можем сделатьunowned
константа ссылок черезlet
.
... и что, возможно, компилятор может сделать больше эффективная оптимизация по этой причине.
это правда, или за кулисами происходит что – то еще, что дает убедительный аргумент для сохранения обоих ключевых слов (хотя небольшое различие основано на трафике переполнения стека – очевидно, запутывает новых и опытных разработчиков).
мне было бы очень интересно услышать от людей, которые работали над компилятором Swift (или другими компиляторами).
2 ответов
мой вопрос в том, какой смысл иметь две такие похожие концепции? Каковы внутренние различия, которые требуют наличия двух ключевых слов для того, что кажется по существу 99% то же самое?
они совсем не похожи. Они настолько разные, насколько это возможно.
weak
- очень сложная концепция, введенная при введении ARC. Он выполняет почти чудесную задачу, позволяя вам предотвратить сохранение цикл (избегая сильной ссылки) без риска сбоя от болтающегося указателя, когда ссылочный объект выходит из существования - то, что раньше происходило все время до появления ARC.unowned
, С другой стороны, это non-дуга слабая (если быть точным, это то же самое, что и не дугаassign
). Это is то, чем мы привыкли рисковать, это is что вызвало так много сбоев, прежде чем была введена ARC. Он это очень опасно, потому что вы можете получить болтающийся указатель и сбой, если ссылочный объект выходит из существования.
причина разницы в том, что weak
, чтобы совершить свое чудо, включает в себя много дополнительных накладных расходов для среды выполнения, вставленных за кулисы компилятором. weak
ссылки управляются памятью для вас. В частности, среда выполнения должна поддерживать Блокнот всех ссылки, помеченные таким образом, отслеживают их, чтобы, если объект со слабой ссылкой выходит из существования, среда выполнения может найти эту ссылку и заменить ее на nil
чтобы предотвратить свисающий указатель.
в Swift, как следствие, a weak
ссылка всегда является необязательной (именно так, чтобы ее можно было заменить на nil
). Это дополнительный источник накладных расходов, потому что работать с дополнительным влечет за собой дополнительную работу, так как он всегда должен быть развернут, чтобы получить все, что с ним сделают.
по этой причине unowned
всегда лучше там, где это применимо. Но никогда не используйте его, если это абсолютно безопасно! С unowned
, вы выбрасывать автоматическое управление памятью и безопасность. Вы намеренно возвращаетесь к плохим старым временам до дуги.
в моем использовании общий случай возникает в ситуациях, когда закрытие нуждается в список захвата с участием self
во избежание сохраняйте цикл. В такой ситуации почти всегда можно сказать [unowned self]
в списке захвата. Когда мы делаем:
это более удобно для программиста, потому что нет ничего, чтобы развернуть.
[weak self]
было бы опционным в потребности разворачивать для использования его.это более эффективно, отчасти по той же причине (разворачивание всегда добавляет дополнительный уровень косвенности), а отчасти потому, что это одна менее слабая ссылка для список scratchpad среды выполнения для отслеживания.
A weak
ссылка фактически установлена на ноль, и вы должны проверить ее, когда референт освобождает и unowned
один установлен в ноль, но вы не обязаны его проверить.
вы можете проверить weak
против нуля с if let
, guard
, ?
и т. д., Но нет смысла проверять unowned
, потому что вы думаете, что это невозможно. Если вы ошибаетесь, вы терпите крах.
я обнаружил, что на практике я никогда не использую unowned. Есть мизер производительности, но дополнительная безопасность от использования слабых стоит того.
Я бы оставил неиспользуемое использование для очень конкретного кода, который должен быть оптимизирован, а не общий код приложения.
"почему он существует", который вы ищете, это то, что Swift предназначен для написания системного кода (например, ядра ОС), и если у них не было самых основных примитивов без дополнительного поведения, они не могли этого сделать.
примечание: Я ранее сказал в этом ответе, что unowned не установлен до нуля. Это неправильно, голый unowned
имеет значение nil. А unowned(unsafe)
не имеет значения nil и может быть болтающимся указателем. Это для высокопроизводительных потребностей и, как правило, не должно быть в коде приложения.