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