Слабый и неспокойный в Свифте. Каковы внутренние различия?

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