为什么通过使用局部变量弱化强引用不起作用?
Why weakifying a strong reference by using a local variable doesn't work?
(我了解 ARC 的工作原理以及 weak
和 unowned
之间的区别。问题是关于它们的具体用途以及为什么它不起作用。我将使用 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,说明字典中保存了对该对象的强引用。
我想知道为什么? weak
和 unowned
关键字是否仅适用于 属性?但是上面的代码不会产生编译器错误并且 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 的回答包含了我将在下面给出的所有要点。但我会尽量让它们更明确一点:
- 变量代表一个存储(内存中的一个位置)
- 赋值操作改变存储中的值
weak
和unowned
是存储的属性。它们不受赋值操作的影响。
所以我的示例代码中第 10 行的 unowned
关键字只影响特定的存储位置(它在堆栈中)并且对全局字典使用的存储属性没有影响(正如@Sweeper 指出的那样)出)。
(我了解 ARC 的工作原理以及 weak
和 unowned
之间的区别。问题是关于它们的具体用途以及为什么它不起作用。我将使用 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,说明字典中保存了对该对象的强引用。
我想知道为什么? weak
和 unowned
关键字是否仅适用于 属性?但是上面的代码不会产生编译器错误并且 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
ind
is set to the (unowned) referenceu
.
它在说:
The value associated with the key
u.uuid
ind
is a reference (not saying what kind) that refers to whatu
is referring to.
u
是无主的事实是无关紧要的。字典将始终存储对对象的强引用。这就是它们的设计方式。
在 Weak<T>
wrapper 的情况下,字典仍将存储对 Weak<T>
的强引用,但 Weak<T>
将存储对包装的 T
的弱引用目的。这就是它如何实现没有对 T
对象的强引用。
@Sweeper 的回答包含了我将在下面给出的所有要点。但我会尽量让它们更明确一点:
- 变量代表一个存储(内存中的一个位置)
- 赋值操作改变存储中的值
weak
和unowned
是存储的属性。它们不受赋值操作的影响。
所以我的示例代码中第 10 行的 unowned
关键字只影响特定的存储位置(它在堆栈中)并且对全局字典使用的存储属性没有影响(正如@Sweeper 指出的那样)出)。