Почему ослабление сильной ссылки с помощью локальной переменной не работает?

(Я понимаю, как работает 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- это ссылка (не говоря о том, какой именно), которая относится к тому, о чем идет речь.

Дело в том, что uunowned скорее не имеет значения. Словари всегда будут хранить сильные ссылки на объекты. Вот как они устроены.

В случае оболочки словарь по-прежнему будет хранить сильную ссылку на, но Weak<T>сохранит слабую ссылку на завернутый объект. Вот как достигается отсутствие четкой ссылки на T объект.

Ответ @Sweeper содержит все моменты, которые я приведу ниже. Но я постараюсь сделать их более явными:

  • Переменная представляет собой хранилище (место в памяти)
  • Операция присвоения изменяет значение в хранилище
  • weakи являются атрибутами хранилища. На них не влияет операция присваивания.

Так что unowned ключевое слово в строке 10 в моем примере кода влияет только на это конкретное место хранения (оно в стеке) и не влияет на атрибут хранилища, используемый глобальным словарем (как указал @Sweeper).

Другие вопросы по тегам