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-ARCassign
). 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.
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 aBone
. And aBone
can exists without aDog
.
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 insideCreditCard
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.
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!
Swift. Is the (absolutely) sole specific advantage of unowned over weak, performance?
I agree with Yannick. Your bold statements are not correct. An unowned reference must be valid for its lifetime. In an -Ounchecked
program, failure to maintain this precondition is undefined behavior. I don't mean "it crashes." I mean it is not a well-formed program; it is undefined what it does. A weak reference cannot generate undefined behavior due to its release, even under -Ounchecked
.
Using unowned
is a statement by the programmer that the reference will be valid over its entire lifetime. That's not even something Type!
asserts. !
types just assert that the reference will be valid at the point that it is accessed. That's why you can't test x == nil
on an unowned. It is not optional. It's not "optional in disguise" (like Type!
). It must always be valid.
Unlike a weak reference, however, an unowned reference is used when the other instance has the same lifetime or a longer lifetime. ... An unowned reference is expected to always have a value. —— [The Swift Programming Language]
So to your "deepest possible philosophical," unowned includes a precondition that does not exist in weak. This precondition exists outside the program, and must be proven by programmer, not the compiler, in order to ensure a well-formed program.
To whether there is a reason to use unowned
, there certainly is if we're taking an absolutest stance (as in your question). It is the tightest type in cases where the precondition is known to be true. weak
is a weaker type than unowned
; it expresses fewer preconditions. Good type theory encourages us to use the strongest (most restrictive; fewest legal values) types we can, and unowned
is a stronger type than weak
.
In a non-absolutist ("practical") sense, the result of picking a stronger type is simpler code. When you use weak
, you have to constantly re-assert the precondition that it is not nil
every time you use it and handle the cases where it is (possibly inserting fatalError
which just reinvents unowned
with more work). Using unowned
lets you assert this precondition one time. This creates simpler, more correct code. I've never used unowned
for speed. I've always used it to avoid answering over and over again "but what if it's nil?" in code where it must never be nil.
What is the difference in Swift between 'unowned(safe)' and 'unowned(unsafe)'?
From what I understand, although I can't find a definitive source from Apple, unowned
can be broken into two flavors, safe
and unsafe
.
A bare unowned
is unowned(safe)
: it is a specially wrapped reference which will throw an exception when a dealloced instance is referenced.
The special case is unowned(unsafe)
: it is the Swift equivalent of Objective C's @property (assign)
or __unsafe_unretained
. It should not be used in a Swift program, because its purpose is to bridge to code written in Objective C.
So, you will see unowned(unsafe)
when looking at the import wrapper for Cocoa classes, but don't use it unless you have to, and you will know when you have to.
Update
__unsafe_unretained
is a simple pointer. It will not know when the instance being pointed at has be dealloced, so when it's dereferenced, the underlying memory could be garbage.
If you have a defect where a dealloced __unsafe_unretained
variable is being used, you will see erratic behavior. Sometimes enough of that memory location is good enough so the code will run, sometimes it will have been partially overwritten so you will get very odd crashes, and sometimes that memory location will contain a new object so you will get unrecognized selector exceptions.
Transitioning to ARC Release Notes
__unsafe_unretained
specifies a reference that does not keep the referenced object alive and is not set to nil when there are no strong references to the object. If the object it references is deallocated, the pointer is left dangling.
Understanding weak and unowned reference in Swift under the hood
Okay, i found out.
- Unowned link points to the object as well as strong.
- Unowned link faster than weak.
- Side table stores strong RC, weak RC, unowned RC, link to the object and some flags
What's different between ? and ! in weak, strong reference in Swift
So can you guys explain for me, what's different between ? and ! in
authorObj!.book?.author = authorObj and authorObj!.book!.author =
authorObj?
When you use ?
to unwrap an optional it is referred to as optional chaining. If the optional is nil
, the result of the entire chain will be nil
. The advantage of using ?
is that your app won't crash if the value being unwrapped is nil
.
So:
authorObj!.book?.author = authorObj
will crash if authorObj
is nil
(because of the forced unwrap !
).
and:
authorObj!.book!.author = authorObj
will crash if either authorObj
or book
is nil
.
The safe way to write this would be:
authorObj?.book?.author = authorObj
If authorObj
or book
is nil
, this will do nothing and it won't crash.
authorObj is a strong reference same as authorObj.book.author, it's
strong reference too? Because it dont have weak or unowned before var.
It only makes sense to talk about a single variable when talking about weak vs. strong. It doesn't make sense to ask if authorObj.book
is weak; you can say that Author
holds a weak reference to book
.
Only authorObj.book is weak reference. But when I assign authorObj to
nil, all are deinited. Why? I assign only authorObj to nil but
Author() instance still have 1 strong reference authorObj.book.author
When you assign nil
to authorObj
, that was the last strong reference to authorObj
, so Automatic Reference Counting (ARC) decrements the reference counter and then frees all of the references inside of authorObj
. If those are strong references, it decrements the reference count and if that was the last reference to that object, the object is freed as well. If any other object is holding a weak reference to any object that is freed, then ARC will set that value to nil
in all of the weak pointers.
To test this in a playground, put your commands inside a function called test
and add print
statements so that you can see when things happen.
class Author {
weak var book: Book?
deinit {
print("Dealloc Author")
}
}
class Book {
var author: Author?
deinit {
print("Dealloc Book")
}
}
func test() {
print("one")
var authorObj: Author? = Author()
print("two")
authorObj!.book = Book()
print("three")
authorObj!.book?.author = authorObj
print("four")
}
test()
Output:
one
two
Dealloc Book
three
four
Dealloc Author
The thing to note is that the Book
is deallocated before step three
. Why? Because there are no strong pointers to it. You allocated it and then assigned the only reference to it to a weak pointer inside of Author, so ARC immediately freed it.
That explains why authorObj!.book!.author = authorObj
crashes, because authorObj!.book
is nil
since the Book
which was just assigned to it has been freed.
Now, try assigning Book()
to a local variable book
:
func test() {
print("one")
var authorObj: Author? = Author()
print("two")
let book = Book()
authorObj!.book = book
print("three")
authorObj!.book?.author = authorObj
print("four")
authorObj = nil
print("five")
}
test()
This time, the output is quite different:
one
two
three
four
five
Dealloc Book
Dealloc Author
Now, the local variable book
holds a strong reference to the Book
that was allocated, so it doesn't get immediately freed.
Note, even though we assigned nil
to authorObj
in step four
, it wasn't deallocated until after book
was deallocated after step five
.
The local variable book
holds a strong reference to Book()
, and Book
holds a strong reference to Author
, so when we assign nil
to authorObj
in step four
, the authorObj
can't be freed because book
still holds a strong reference to it. When test
ends, the local variable book
is freed, so the strong reference to authorObj
is freed, and finally authorObj
can be deallocated since the last strong reference to it is gone.
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.
Related Topics
Convert Opengl Shader to Metal (Swift) to Be Used in Cifilter
iOS Tabbar Item Title Issue in iOS13
How to Detect That Parameter Is a Tuple of Two Arbitrary Types
Early Return from a Void-Func in Swift
Swift Lazy Subscript Ignores Filter
Convert Emoji to Hex Value Using Swift
Treat *Some* Warnings as Errors in Swift
Animate the Fractioncomplete of Uiviewpropertyanimator for Blurring the Background
Separation of Function Declaration and Definition in Swift
Swift - Class Method Which Must Be Overridden by Subclass
How to Convert Delegate to Observable Rxswift
Reversing the Order of a String Value
How to Get the Realy Fixed Device-Id in Swift
Result Values in '? :' Expression Have Mismatching Types 'Some View' and '...'
Navigationview Doesn't Display Correctly When Using Tabview in Swiftui
Getting Unresolved Identifier 'Self' in Swiftui Code Trying to Use Timer.Scheduledtimer
Swift Bindings Won't Work Xcode 6 Beta 5
Swiftui @Fetchrequest Core Data Changes to Relationships Don't Refresh