Difference Between a Weak Reference and an Unowned Reference

What is the difference between a weak reference and an unowned reference?

Both weak and unowned references do not create a strong hold on the referred object (a.k.a. they don't increase the retain count in order to prevent ARC from deallocating the referred object).

But why two keywords? This distinction has to do with the fact that Optional types are built-in the Swift language. Long story short about them: optional types offer memory safety (this works beautifully with Swift's constructor rules - which are strict in order to provide this benefit).

A weak reference allows the possibility of it to become nil (this happens automatically when the referenced object is deallocated), therefore the type of your property must be optional - so you, as a programmer, are obligated to check it before you use it (basically the compiler forces you, as much as it can, to write safe code).

An unowned reference presumes that it will never become nil during its lifetime. An unowned reference must be set during initialization - this means that the reference will be defined as a non-optional type that can be used safely without checks. If somehow the object being referred to is deallocated, then the app will crash when the unowned reference is used.

From the Apple docs:

Use a weak reference whenever it is valid for that reference to become
nil at some point during its lifetime. Conversely, use an unowned
reference when you know that the reference will never be nil once it
has been set during initialization.

In the docs, there are some examples that discuss retain cycles and how to break them. All these examples are extracted from the docs.

Example of the weak keyword:

class Person {
let name: String
init(name: String) { self.name = name }
var apartment: Apartment?
}

class Apartment {
let number: Int
init(number: Int) { self.number = number }
weak var tenant: Person?
}

And now, for some ASCII art (you should go see the docs - they have pretty diagrams):

Person ===(strong)==> Apartment
Person <==(weak)===== Apartment

The Person and Apartment example shows a situation where two properties, both of which are allowed to be nil, have the potential to cause a strong reference cycle. This scenario is best resolved with a weak reference. Both entities can exist without having a strict dependency upon the other.

Example of the unowned keyword:

class Customer {
let name: String
var card: CreditCard?
init(name: String) { self.name = name }
}

class CreditCard {
let number: UInt64
unowned let customer: Customer
init(number: UInt64, customer: Customer) { self.number = number; self.customer = customer }
}

In this example, a Customer may or may not have a CreditCard, but a CreditCard will always be associated with a Customer. To represent this, the Customer class has an optional card property, but the CreditCard class has a non-optional (and unowned) customer property.

Customer ===(strong)==> CreditCard
Customer <==(unowned)== CreditCard

The Customer and CreditCard example shows a situation where one property that is allowed to be nil and another property that cannot be nil has the potential to cause a strong reference cycle. This scenario is best resolved with an unowned reference.

Note from Apple:

Weak references must be declared as variables, to indicate that their
value can change at runtime. A weak reference cannot be declared as a
constant.

There is also a third scenario when both properties should always have a value, and neither property should ever be nil once initialization is complete.

And there are also the classic retain cycle scenarios to avoid when working with closures.

For this, I encourage you to visit the Apple docs, or read the book.

In Swift, unowned vs. weak reference

Strong & Weak references

A weak reference is a reference that does not keep a strong hold on the instance it refers to, and so does not stop ARC from disposing of the referenced instance.

So when A has a weak reference to B, then A is NOT the owner.

Example (where A is Bone and B is Dog)

class Dog {
var bone: Bone?
}

class Bone {
weak var belongsTo: Dog?
}

Strong Reference

Here a Dog can have a Bone. In that case it's the owner of that Bone. So the bone property is a strong reference.

Weak reference
The Bone can belong to a Dog. But we need to declare the belongsTo property as weak, otherwise we have a strong retain cycle (which means ARC is not going to release these object once we are done with them).

Important: In this scenario a Dog can exists without a Bone. And a Bone can exists without a Dog.

Unowned reference

Let's look at another example

class Person {
var creditCard: CreditCard?
}

class CreditCard {
unowned var owner: Person

init(owner: Person) {
self.owner = owner
}
}

Again, Person can own a CreditCard, so it has a the owner property which is a strong reference to CreditCard.

However a CreditCard CANNOT exist without a person. Right?
So inside CreditCard we want a property which will always be populated but we also want it to be weak.

Something like this

weak var owner: Person 
error: 'weak' variable should have optional type 'Person?'

However a weak property must be declared as Optional so we use the unowned which means:

I want a weak reference and it will always be populated.

weak vs unowned in Swift. What are the internal differences?

My question is, what is the point in having two such similar concepts? What are the internal differences that necessitate having two keywords for what seem essentially 99% the same thing?

They are not at all similar. They are as different as they can be.

  • weak is a highly complex concept, introduced when ARC was introduced. It performs the near-miraculous task of allowing you to prevent a retain a cycle (by avoiding a strong reference) without risking a crash from a dangling pointer when the referenced object goes out of existence — something that used to happen all the time before ARC was introduced.

  • unowned, on the other hand, is non-ARC weak (to be specific, it is the same as non-ARC assign). It is what we used to have to risk, it is what caused so many crashes, before ARC was introduced. It is highly dangerous, because you can get a dangling pointer and a crash if the referenced object goes out of existence.

The reason for the difference is that weak, in order to perform its miracle, involves a lot of extra overhead for the runtime, inserted behind the scenes by the compiler. weak references are memory-managed for you. In particular, the runtime must maintain a scratchpad of all references marked in this way, keeping track of them so that if an object weakly referenced goes out of existence, the runtime can locate that reference and replace it by nil to prevent a dangling pointer.

In Swift, as a consequence, a weak reference is always to an Optional (exactly so that it can be replaced by nil). This is an additional source of overhead, because working with an Optional entails extra work, as it must always be unwrapped in order to get anything done with it.

For this reason, unowned is always to be preferred wherever it is applicable. But never use it unless it is absolutely safe to do so! With unowned, you are throwing away automatic memory management and safety. You are deliberately reverting to the bad old days before ARC.

In my usage, the common case arises in situations where a closure needs a capture list involving self in order to avoid a retain cycle. In such a situation, it is almost always possible to say [unowned self] in the capture list. When we do:

  • It is more convenient for the programmer because there is nothing to unwrap. [weak self] would be an Optional in need of unwrapping in order to use it.

  • It is more efficient, partly for the same reason (unwrapping always adds an extra level of indirection) and partly because it is one fewer weak reference for the runtime's scratchpad list to keep track of.

Optional unowned reference versus weak in Swift 5.0

You've misunderstood the release note and the meaning of the change in the language.

why Apple decided to make the unowned an optional type

They didn't. You can, and usually will, still say

unowned let owner : MyViewController

The only change here is that the unowned variable can be an Optional, which was illegal previously. This change takes care of an annoying edge case, that's all.

Above isn't true anymore

Yes, it is. Things are completely unchanged from before:

  • Weak references must be typed as Optional; they do not retain the object referred to, but they track the object referred to, and revert to nil if that object goes out of existence.
  • Unowned references do not retain the object referred to and do not track the object referred to, so it's up to you to prevent that object from going out of existence or you may end up with a dangling pointer and a crash.

The only thing that's changed is that there used to be an additional rule that an unowned reference type could not be an Optional. That rule is now gone.

As you rightly point out, if the unowned reference type is an Optional, this must be a var reference, not a let reference (because having this be an Optional would make no sense if you didn't have the power to change it from nil to an actual value and vice versa).

A typical use case is very much like what you yourself provided:

class Node {
unowned var parent: Node?
}

It seems reasonable to say that this Node may or may not have a parent (because it might be at the top of the graph), but that if it does have a parent, that parent should be unowned (a parent should retain its child, but a child should not retain its parent). Previously, the only way to say that was to make this a weak reference, which entails some unnecessary overhead, and is otiose, because we can absolutely guarantee that if a node has a parent, the parent will outlive the child. Now, you can say what you mean, which is generally a good thing.

unowned vs. weak. Why we should prefer unowned?

Weak references are automatically set to nil once the object they point to gets deallocated. For this to be possible in Swift, those must be declared as var and optional:

class SomeOtherClass {
weak var weakProperty: SomeClass?
}

This is fine if the weakProperty can become nil while the instance of SomeOtherClass is still alive and we want to check for that before using it (delegates are one such example). But what if some reference should never logically be nil and we still want to prevent a retain cycle? In Objective-C any object reference can be nil (and messaging nil always fails silently) so there is no dilemma, we always use weak. But Swift doesn't have nilable references at all. We use optionals for something that can semantically lack value. But we shouldn't be forced to use optionals for something that must always have value, just to be able to break a retain cycle. Such practice would go against the intended semantics of optionals.

That's where unowned comes in. It comes in two flavours - unowned(safe) and unowned(unsafe). The latter is dangerous and it's equivalent to assign and unsafe_unretained from Objective-C. But the former, which is the default one (at least while debugging; not sure if they optimise it to unowned(unsafe) in release builds), will reliably crash your app if the referenced object gets prematurely deallocated. Sure, your app will crash if something goes wrong, but that's much easier to debug than failing silently. It should only fail silently when you actually want that (in which case you would use weak)

Understanding weak and unowned reference in Swift under the hood

Okay, i found out.

  1. Unowned link points to the object as well as strong.
  2. Unowned link faster than weak.
  3. Side table stores strong RC, weak RC, unowned RC, link to the object and some flags

Difference Between weak & unowned in respect to ARC memory management in Swift 3.1

The most important difference is that unowned variables are very dangerous in Swift.

weak is an optional type, unowned is NOT.

This means that you can create code that uses weak as part of the logic. (think of asynchronous actions that take place only if a view controller is still being shown on the screen, when the code is ran, if the reference is "weak" it will fail silently without causing any other issues if the code is written correctly)

On the other hand, when a variable is unowned you are basically saying that this variable will always refer to something. And unlike weak, if you call it and there's nothing it will crash.

You generally never wanna use unowned. (I haven't come across any case where I had to). On the other hand, "weak self" variables are quite common when writing blocks.

You can see a good explanation on this question:

Shall we always use [unowned self] inside closure in Swift

EDIT: Actually, check the first and second most voted answers. They provide a clear explanation on WHEN to use unowned and how it works. The second even has pictures!

For swift references within view model, should self reference be weak or unknown?

You said:

I … was a little thrown off by the quote above. Am I missing something?

The difference between weak and unowned is merely that when the object is deallocated, it will go through an extra step and go back and nil the weak references, but not the for unowned references. The code with unowned references can therefore be slightly more efficient. But one must be scrupulous about when you use unowned, as the app will crash if you try to use that reference after that object has been deallocated.

What are best practices within the view model?

Personally, I would just use weak. The overhead is immaterial and the presence of asynchronous code significantly complicates the reasoning about unowned references and whether the object be deallocated by the time one reaches the unowned reference.

Lastly, within the closure I am setting self to optional, should I force unwrap? Is there any case in which a view model would be deallocated from memory?

You absolutely do not want to force unwrap whenever dealing with asynchronous code. What if the view and its associated view model were deallocated by the time the asynchronous completion handler code runs?! You should only force unwrap if you know that it can never be nil (which is not the case here).



Related Topics



Leave a reply



Submit