(I understand how ARC works and the difference between weak
and unowned
. The question is about a specific use of them and why it doesn't work. I'll use unowned
in the example below just for simplicity.)
See example below. Note line 10, which is intended to change the passed strong reference to an unowned reference. I thought this would work, but when I used it in my code recently I found I was wrong.
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())
Run the above code in Playground. The result shows that deinit isn't called, indicating a strong reference to the object is saved in the dictionary.
I wonder why? Does weak
and unowned
keyword only applies to property? But the above code doesn't generate compiler error and the Swift book does mention it can be used in variable declaration:
You indicate an unowned reference by placing the unowned keyword before a property or variable declaration.
Can anyone share how you understand it? Thanks!
BTW, I know how to solve the issue (for example, using a wrapper like this). What I try to understand is why the above code doesn't work.
When assigning (
a = b
), you can't control what kind of referencea
is. You can only control what objecta
refer to.Here:
The code is not saying:
It's saying:
The fact that
u
is unowned is rather irrelevant. Dictionaries will always store strong references to objects. That's just how they are designed.In the case of the
Weak<T>
wrapper, the dictionary will still store a strong reference toWeak<T>
, butWeak<T>
will store a weak reference to the wrappedT
object. That's how it achieves not having a strong reference to theT
object.