I'm confused on this topic in swift where it is said that unowned references must always have a value and cannot be optional, also meaning they cannot be set to 'nil'....well I just saw a program on the Apple documents for swift that instance 'A' with an unowned reference to instance 'B' was deinitialized and deallocated right after instance 'B' was deinitialized/deallocated......when a var is deinitialzed/dealloc doesn't it mean they are set to 'nil'??? Instance B is an optional so sure it can hold 'nil' but why did instance 'A' get deinitialized when its supposed to always have a value????
PS: If this helps..... instance 'B' was an optional type with a strong reference to instance 'A'
The point of an unowned
reference is to hold a weak reference to something that you are guaranteeing (based on your application logic) will not be deallocated prior to the object that has the unowned
reference. You can read more in the documentation.
In a sense it is a similar thing to an implicitly unwrapped optional type (such as String!
). You're telling the compiler that you won't ever access the value when it is nil
, and if you do your program will crash.
It is meaningless to talk about what an unowned
variable "holds" after the object it points to has been deallocated, because Swift guarantees that your app will crash if you ever try to access the variable after the object it points to has been deallocated:
Note also that Swift guarantees your app will crash if you try to
access an unowned reference after the instance it references is
deallocated. You will never encounter unexpected behavior in this
situation. Your app will always crash reliably, although you should,
of course, prevent it from doing so.
An object is deinitialized when its strong reference count drops to 0, but it is not deallocated until its weak reference count also drops to zero.
"Deinitializing" an object means that its deinit
function is executed if it has one, releasing any resource that it holds, and clearing any references that it may have (potentially deinitializing and deallocating more objects). "Deallocating" is when the memory is reclaimed by the runtime. A deinitialized object's reference counting header is still valid.
When you access a weak
reference, the Swift runtime ensures that the object is still in an initialized state. If it isn't, the weak reference is set to nil
and the deinitialized object's weak reference count is decremented.
Unowned references also count towards the weak reference count. When you access an unowned reference, the Swift runtime also ensures that the object is in an initialized state; but if it is not, instead of clearing the reference (it can't do that because it is not optional), it crashes your program.
This effectively makes an unowned reference behave like an implicitly-unwrapped optional, whereas a weak reference behaves like an optional.
The tradeoff for self-zeroing weak references and clean-crashing unowned references is that an object's backing memory cannot be reclaimed until all of its weak references have been tested or deinitialized, and until all of its unowned references have been deinitialized.
Source: Swift runtime code