为什么通过使用局部变量弱化强引用不起作用?

Why weakifying a strong reference by using a local variable doesn't work?

(我了解 ARC 的工作原理以及 weakunowned 之间的区别。问题是关于它们的具体用途以及为什么它不起作用。我将使用 unowned 在下面的示例中只是为了简单起见。)

参见下面的示例。注意第 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,说明字典中保存了对该对象的强引用。

我想知道为什么? weakunowned 关键字是否仅适用于 属性?但是上面的代码不会产生编译器错误并且 Swift book 确实提到它可以用于变量声明:

You indicate an unowned reference by placing the unowned keyword before a property or variable declaration.

谁能分享一下你是怎么理解的?谢谢!

顺便说一句,我知道如何解决这个问题(例如,使用像 this 这样的包装器)。我试图理解的是为什么上面的代码不起作用。

赋值(a = b)时,你无法控制a是哪种引用。您只能控制 a 引用的对象。

这里:

d[u.uuid] = u

代码是不是说:

The value associated with the key u.uuid in d is set to the (unowned) reference u.

它在说:

The value associated with the key u.uuid in d is a reference (not saying what kind) that refers to what u is referring to.

u 是无主的事实是无关紧要的。字典将始终存储对对象的强引用。这就是它们的设计方式。

Weak<T> wrapper 的情况下,字典仍将存储对 Weak<T> 的强引用,但 Weak<T> 将存储对包装的 T 的弱引用目的。这就是它如何实现没有对 T 对象的强引用。

@Sweeper 的回答包含了我将在下面给出的所有要点。但我会尽量让它们更明确一点:

  • 变量代表一个存储(内存中的一个位置)
  • 赋值操作改变存储中的值
  • weakunowned是存储的属性。它们不受赋值操作的影响。

所以我的示例代码中第 10 行的 unowned 关键字只影响特定的存储位置(它在堆栈中)并且对全局字典使用的存储属性没有影响(正如@Sweeper 指出的那样)出)。