Why do I have to unwrap a weak self?
self is inside a completion handler so it might not be there anymore once the callback gets fired (it might be a network operation or something that take some take and won't return a result for several seconds if not more).
You could check if self exists before accessing it instead of unwrapping:
VerifyObject.checkPause(withID: "abcde",
runOnPause: {[weak self] (objectID) in
guard let self = self else { return }
self.doSomething()
})
Or even shorter only doSomething
if self is not nil:
VerifyObject.checkPause(withID: "abcde",
runOnPause: {[weak self] (objectID) in
self?.doSomething()
})
Or if you're absolutely sure that self will exist:
VerifyObject.checkPause(withID: "abcde",
runOnPause: {(objectID) in
self.doSomething()
})
Just be mindful that this last one might cause reain cicles in case where the 2 objects have a strong reference to each other and they will never get deallocated.
In Swift, if I have a closure capturing [weak self], is it good practice to unwrap the optional self at the beginning of the closure?
I believe that the first implementation is better because self could become nil between the statements
And that's why the second implementation is in fact better! If self
is not nil at the first statement, the first statement makes it so that self
couldn't become nil
between the statements. It retains self
exactly for the remainder of the block. This is called "the weak–strong dance".
guard let self = self else { return }
// ^^^^ this self is _strong_, not weak; it retains self
Is it the right way using `[weak self]` in swift closure?
Your pattern has race condition. If self
was deallocated at the exact same time as your completion handler closure was executing, it could crash. As a general rule, avoid using the !
forced unwrapping operator if you can.
I’d lean towards the
guard
“early exit” pattern (reducing nested braces, making code easier to read). The standard Swift 4.2 solution is:someTask { [weak self] result in
guard let self = self else { return }
self.xxx = yyy
self.doLongTermWork()
self.finish()
}Before Swift 4.2, which implemented SE-0079, we would have to do something like:
someTask { [weak self] result in
guard let strongSelf = self else { return }
strongSelf.xxx = yyy
strongSelf.doLongTermWork()
strongSelf.finish()
}You can see why we prefer the Swift 4.2 improvement, as this
strongSelf
syntax is inelegant.The other obvious alternative is just:
someTask { [weak self] result in
self?.xxx = yyy
self?.doLongTermWork()
self?.finish()
}Sometimes you need the “weak self - strong self dance” (the first two alternatives), but it would not appear to be the case here. This is likely sufficient.
There are other scenarios/edge cases that one might contemplate, but these are the basic approaches.
Where does the weak self go?
First of all, note that you generally don't need to worry about retain cycles with DispatchQueue.main.asyncAfter
, as the closure will be executed at some point. Therefore whether or not you weakly capture self
, you won't be creating a permanent retain cycle (assuming that tickle.fresh
also doesn't).
Whether or not you put a [weak self]
capture list on the outer asyncAfter
closure depends entirely on whether you want self
to be retained until the closure is called (after the time you set). If you don't need self
to remain alive until the closure is called, put [weak self]
in, if you do, then don't put it in.
Whether or not you put a [weak self]
on the inner closure (the one passed to tickle.fresh
) depends on whether you've already weakly captured self
in the outer closure. If you haven't, then you can put [weak self]
in order to prevent the inner closure from retaining it. If however, the outer closure has already weakly captured self
, then the inner closure will already have a weak reference to self
, thus adding [weak self]
to the inner closure will have no effect.
So, to summarise:
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
tickle.fresh { msg in
self.paint()
}
}
self
will be retained by both the outer and inner closure.
DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in
tickle.fresh { msg in
self?.paint()
}
}
self
will not be retained by either closure.
DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in
tickle.fresh { [weak self] msg in
self?.paint()
}
}
Same as the above, the additional [weak self]
for the inner closure has no effect, as self
is already weakly captured by the outer closure.
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
tickle.fresh { [weak self] msg in
self?.paint()
}
}
self
will be retained by the outer closure, but not the inner closure.
Of course, it might be that you don't want self
to be retained by the outer closure, but you do want it to be retained by the inner closure. In such cases, you can declare a local variable in the outer closure in order to hold a strong reference to self
, when you can then capture in the inner closure:
DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in
guard let strongSelf = self else { return }
tickle.fresh { msg in
strongSelf.paint()
}
}
Now, self
won't be kept alive by the outer closure, but once it's called, if self
still exists, it will be kept alive by the inner closure until that closure has been deallocated.
In response to:
Is a strong reference to a weak reference, a weak or strong reference?
Weak references are implemented as optionals, which are value types. Therefore you cannot directly have a strong reference to one – instead you first have to unwrap it, and then take a strong reference to the underlying instance. In this case you're simply dealing with a strong reference (exactly like my example above with strongSelf
).
However, if a weak reference is boxed (this happens with closure capture – the value type will be put into a heap-allocated box) – then you can indeed have a strong reference to that box. The effect of this is equivalent to a weak reference to the original instance, you just have an invisible bit of extra indirection.
In fact, this is exactly what happens in the example where the outer closure weakly captures self
and the inner closure 'strongly captures' that weak reference. The effect is that neither closure retains self
.
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
Is it safe to force unwrap variables that have been optionally accessed in the same line of code?
Optional Chaining
from "The Swift Programming Language"
gives the following example:
let john = Person()
// ...
let someAddress = Address()
// ...
john.residence?.address = someAddress
followed by (emphasis added):
In this example, the attempt to set the address property of john.residence will fail, because john.residence is currently nil.
The assignment is part of the optional chaining, which means none of the code on the right hand side of the = operator is evaluated.
Applied to your case: In
self?.variable = self!.otherVariable
the right-hand side is not evaluated if self
is nil
.
Therefore the answer to your question
If self indeed is nil, the second part will never happen?
is "yes". With regard to the second question
And it will never happen that self could be 'nilled' during this single line of code?
My original assumption was that once self
has been determined to be != nil
,
a strong reference to self!
is held throughout the evaluation of the
statement, so that this can not happen. However (as @Hamish pointed out),
this is not guaranteed. Apple engineer Joe Groff writes at Confirming order of operations in
the Swift forum:
This isn't guaranteed. Releases may be optimized to happen earlier than this, to any point after the last formal use of the strong reference. Since the strong reference loaded in order to evaluate the left-hand side
weakProperty?.variable
is not used afterward, there is nothing keeping it alive, so it could be immediately released.
If there are any side effects in the getter for variable that cause the object referenced byweakProperty
to be deallocated, nil-ing out the weak reference, then that would cause the force-unwrap on the right side to fail.
You should use if let to test the weak reference, and reference the strong reference bound by theif let
Are `self?` and `guard let self` the same, in a closure?
These are practically identical. The main difference is that the first will check whether self
is nil twice rather than once. Since the first example doesn't hold a strong reference across statements, it is technically possible for the first line to execute, then self
to be released, and the second line not execute. In the second case, the guard let
takes a strong reference until the end of the block, at which point self
will be released.
The latter is generally preferable, though it's not a huge issue either way. It is easier to reason about the guard let
code when self
is nil. When you skip over a bunch of statements using self?.
, any lines that don't rely on self
still execute, which might be surprising. It is also nice in cases where optional chaining isn't appropriate (for example when accessing properties of self
). So it works the same way in more cases.
Are there potential drawbacks to using a [weak self] within a closure after declaring a strong self?
Let's take this step by step (line by line)
// Weak 1
runClosure { [weak self] in
The first line creates a reference to the target object, a reference which coincidentally (or not) is named self
.
self?.isInner = false
The above line makes use of the weak reference, it has no effects on the target object lifecycle.
guard let strongSelf = self else { return }
Now, this line indeed creates a strong reference to the target object, which will extend objects's lifetime by at least the lifetime of strongSelf
. Now depending on the compiler aggressiveness, strongSelf
might die after passing this line (the last reference in code), or when the outer closure finishes executing.
// Can this [weak self] create problems?
// Weak 2
strongSelf.runClosure { [weak self] in
Now this has almost exactly the same effect as the capture from the outer closure. It creates a reference to a possibly already deallocated instance (depending if strongSelf
is still alive at this point or not).
self?.isInner = true
This is the regular optional usage, no effects on target lifetime.
Now, assuming that runClosure
runs asynchronously, there are no issues with the target object living more that expected (assuming there aren't any more strong references out there).
To summarize, an object lifetime is determined by the number of strong references exist to that object. Once all strong references are destroyed, the object will be automatically deallocated. In your particular scenario, the inner closure weakly captures and already weak reference, and this doesn't impact the lifecycle of the target object. The only player is strongSelf
, which gets destroyed no later than the outer closure destroyal.
Referencing [weak self] as self? inside animateWithDuration causes crash
I think the problem here is that self
is special. You've passed the reference to self
weakly into the anonymous function to prevent a retain cycle, but there isn't really an Optional wrapping self
in this story. Thus, the syntactic sugar self?.someView.alpha = 1
— and remember, it is merely syntactic sugar — doesn't work.
It may be that Apple will regard this as a bug; or maybe not. But either way, the solution is to do formulaically exactly what you are doing in the second example: do the weak-strong dance explicitly.
Related Topics
Swift 4 JSONdecoder Optional Variable
Applescript Email Attachment Not Working in Handler
Swiftui Change on Multilevel Children Published Object Change
Why Does a Simple Swift Arithmetic Operation Compile So Slow
Anchor Constraints Not Honored in Xcode 10/iOS 12
Apple Mach-O Linker Error (Static, Not Ld)
Swift Optionals Best Practices
Calling C++ from Swift - What Is The Equivalent of Std::Vector<T>
Parse Nested Completion Handlers
Macos Swift Master-Detail Delegate/Protocol Not Working
Non-Translucent UItabbar Creates Strange Grey Bar
My UIcollectionview Does Not Scroll Smoothly Using Swift
How to Calculate The Camera Position from Vuforia Gl Matrix
Swiftui Map Overlays Without UIviewrepresentable
Does Realm Support Computed Property in Swift
How to Find Multiple Nsrange for a String from Full String iOS Swift