Почему ослабление сильной ссылки с помощью локальной переменной не работает?
(Я понимаю, как работает ARC, и в чем разница между и. Вопрос в том, как их использовать и почему это не работает. Я буду использовать в приведенном ниже примере только для простоты.)
См. Пример ниже. Обратите внимание на строку 10, которая предназначена для замены переданной сильной ссылки на бесхозную. Я думал, что это сработает, но когда я недавно использовал это в своем коде, я обнаружил, что ошибался.
1 import Foundation
2 class MyClass {
3 var uuid: UUID = UUID()
4
5 deinit {
6 print("Deinited!")
7 }
8 }
9 func test(_ d: inout [UUID:MyClass], _ o: MyClass) {
10 unowned let u = o // <- !
11 d[u.uuid] = u
12 }
13 var d = [UUID: MyClass]()
14 test(&d, MyClass())
Запустите приведенный выше код в Playground. Результат показывает, что deinit не вызывается, что указывает на то, что сильная ссылка на объект сохраняется в словаре.
Интересно, почему? Делает
weak
и
unowned
ключевое слово применяется только к собственности? Но приведенный выше код не генерирует ошибку компилятора, и в книге Swift упоминается, что его можно использовать в объявлении переменной:
Вы указываете ссылку без владельца, помещая ключевое слово unowned перед объявлением свойства или переменной.
Может кто-нибудь поделится, как вы это понимаете? Спасибо!
Кстати, я знаю , как решить эту проблему (например, используя оболочку , как это). Я пытаюсь понять, почему приведенный выше код не работает.
2 ответа
При присвоении (
a = b
), вы не можете контролировать, что это за ссылка. Вы можете только контролировать, какой объект
a
Ссылаться на.
Здесь:
d[u.uuid] = u
Код не говорит:
Значение, связанное с ключом, устанавливается на ссылку (без владельца).
Он говорит:
Значение, связанное с ключом
u.uuid
вd
- это ссылка (не говоря о том, какой именно), которая относится к тому, о чем идет речь.
Дело в том, что
u
unowned скорее не имеет значения. Словари всегда будут хранить сильные ссылки на объекты. Вот как они устроены.
В случае оболочки словарь по-прежнему будет хранить сильную ссылку на, но
Weak<T>
сохранит слабую ссылку на завернутый объект. Вот как достигается отсутствие четкой ссылки на
T
объект.
Ответ @Sweeper содержит все моменты, которые я приведу ниже. Но я постараюсь сделать их более явными:
- Переменная представляет собой хранилище (место в памяти)
- Операция присвоения изменяет значение в хранилище
-
weak
и являются атрибутами хранилища. На них не влияет операция присваивания.
Так что
unowned
ключевое слово в строке 10 в моем примере кода влияет только на это конкретное место хранения (оно в стеке) и не влияет на атрибут хранилища, используемый глобальным словарем (как указал @Sweeper).