Shall we always use [unowned self] inside closure in Swift
No, there are definitely times where you would not want to use [unowned self]
. Sometimes you want the closure to capture self in order to make sure that it is still around by the time the closure is called.
Example: Making an asynchronous network request
If you are making an asynchronous network request you do want the closure to retain self
for when the request finishes. That object may have otherwise been deallocated but you still want to be able to handle the request finishing.
When to use unowned self
or weak self
The only time where you really want to use [unowned self]
or [weak self]
is when you would create a strong reference cycle. A strong reference cycle is when there is a loop of ownership where objects end up owning each other (maybe through a third party) and therefore they will never be deallocated because they are both ensuring that each other stick around.
In the specific case of a closure, you just need to realize that any variable that is referenced inside of it, gets "owned" by the closure. As long as the closure is around, those objects are guaranteed to be around. The only way to stop that ownership, is to do the [unowned self]
or [weak self]
. So if a class owns a closure, and that closure captures a strong reference to that class, then you have a strong reference cycle between the closure and the class. This also includes if the class owns something that owns the closure.
Specifically in the example from the video
In the example on the slide, TempNotifier
owns the closure through the onChange
member variable. If they did not declare self
as unowned
, the closure would also own self
creating a strong reference cycle.
Difference between unowned
and weak
The difference between unowned
and weak
is that weak
is declared as an Optional while unowned
is not. By declaring it weak
you get to handle the case that it might be nil inside the closure at some point. If you try to access an unowned
variable that happens to be nil, it will crash the whole program. So only use unowned
when you are positive that variable will always be around while the closure is around
Why would I ever use unowned self?
unowned
has a marginal performance advantage over weak
because the runtime doesn't have to keep track of the reference to turn it into nil
when the object goes away.
In respect of retain cycles (well, strong reference cycles), neither weak
nor unowned
creates a strong reference (in pre ARC terms, neither increments the retain count) so there is no danger of a reference cycle, in fact, that is why you need to specify weak
or unowned
for self
in closures.
Also, with unowned
you can use the reference as a non optional, so you don't have to put any code in the closure to unwrap it.
I always use weak
unless there is a really good performance reason not to.
NB in your code, I do not think either is necessary because the closure is not escaping i.e. The reference to it taken in the function call foo
does not persist after the end of foo
's scope.
When we should NOT use neither [weak self] nor [unowned self]?
You need to use [weak self] or [unowned self] if your closure can cause a Strong Reference Cycle.
This can occur if you assign the closure to a property of self and you refer to self or a property of self inside the closure itself. Closures are reference types, hence essentially the same rules apply to strong references as if you used normal classes.
As for your example, there is no need for [weak self]
or [unowned self]
, since you don't assign the closure to a variable inside the class to which self
refers to, so there won't be a strong reference cycle.
For more information, check out the Strong Reference Cycles for Closures part of the Swift programming language guide. Here is an example from the mentioned link of when a strong reference cycle can be caused by closures:
class HTMLElement {
let name: String
let text: String?
lazy var asHTML: () -> String = {
if let text = self.text {
return "<\(self.name)>\(text)</\(self.name)>"
} else {
return "<\(self.name) />"
}
}
init(name: String, text: String? = nil) {
self.name = name
self.text = text
}
deinit {
print("\(name) is being deinitialized")
}
}
Without [unowned self]
in the closure of asHTML
, a strong reference cycle will be caused by the closure assigned to asHTML
. Changing the implementation of asHTML
to the following solves this issue:
lazy var asHTML: () -> String = {
[unowned self] in
if let text = self.text {
return "<\(self.name)>\(text)</\(self.name)>"
} else {
return "<\(self.name) />"
}
}
Should I use [weak self] if I don't actually reference self in my completion block?
Capturing the variables, happens only when you use it internally, a closure will NEVER capture the variables by default (not like Java inner class which ALWAYS captures this
), so, it you use a variable (including self
) inside the closure, it is captured.
Also you can manually capture the variables using the [weak self]
, [weak your_variable_here]
, [unowned self]
, [unowned your_variable_here]
, [self]
or [your_variable_here]
If the compiler tells you variable "self" is written to but never read from
, it means that you didn't use self
inside, so it is completely safe not to use [weak self]
, because self
will NOT be captured, because it is not used.
weak self
or unowned self
is needed only when your closure captures self
, and escapes the function it is passed to, especially if it is saved in a variable.
Refer to Closures in Apple's Official Swift Documentation
Why does [weak self] work but [unowned self] break in a Swift closure?
This sounds like a bug. {[unowned self] in self.twinkle()}
should work identically to {[weak self] in self!.twinkle()}
Strong, weak and unowned self in closures explanation
It is not possible to say without looking at A.someFunctionA
since it's unknown if completion
is @escaping
(e.g. if it's retained). For the rest of the answer I will assume that it is @escaping
.
Swift needs to ensure runtime safety, and will keep any objects it might need in the future alive, in this case by making a strong reference to self
(since self
is the only variable used inside the closure).
In this scenario there is no reference cycle. This is because instanceA
is not retained, so A => B, but B !=> A.
However, if instanceA
was retained by B
(let's say you create an instanceA: A
property and set it) then you will have a retain cycle.
To get around this you can make variables within the closure either weak
or unowned
. They both do the same thing, but provide you with slightly different types. They both hold a weak reference, meaning that instanceA
will not be increase the reference count of your B
instance; if B
is deallocated and there are no other reference, instanceA
is also deallocated.
When using [weak self]
self
is optional
, e.g. self: B?
. However, [unowned self]
is explicitly unwrapped, e.g. self: B!
. This means that if the closure is called and self
is nil
your program will crash. This is why it's important to only use unowned
when you know for certain that deallocating B
will also deallocate A
. There are a few scenarios where unowned
is safe, e.g. the case when creating a closure and storing it on the same object that created it, but there are more nuances to this.
If unsure, use weak
!
Related Topics
Any Way to Replace Characters on Swift String
How to Enumerate an Enum With String Type
How to Convert Unix Epoch Time to Date and Time in iOS Swift
Getting the Decimal Part of a Double in Swift
Instance Member Cannot Be Used on Type
How to Detect a Tap Gesture Location in Swiftui
Sharing Userdefaults Between Extensions
How to Make a Custom Initializer For a Uiviewcontroller Subclass in Swift
Extra Arguments At Positions #11, #12 in Call Swiftui
Shall We Always Use [Unowned Self] Inside Closure in Swift
Do Swift-Based Applications Work on Os X 10.9/Ios 7 and Lower
How to Save and Read Array of Array in Nsuserdefaults in Swift
Programmatically Detect Tab Bar or Tabview Height in Swiftui
How to Create Local Scopes in Swift
How to Get Monday'S Date of the Current Week in Swift
How to Create a Multi-Line Text Inside a Scrollview in Swiftui