слабый против 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 и может быть болтающимся указателем. Это для высокопроизводительных потребностей и, как правило, не должно быть в коде приложения.