Block retain cycles in Swift? - swift

Traditionally in Objc, we do weakSelf to prevent additional retain count for blocks.
How does swift internally manage retain cycles that occur in blocks for Objc?

To prevent a block from holding a strong reference to an object, you must define a capture list for the block.
The closure expression syntax is defined as follows:
{ ( /*parameters*/ ) -> /*return type*/ in
// statements
}
But this is extended later in the documentation to include a capture list. This effectively equates to the expression syntax being defined as follows:
{ [ /*reference type*/ /*object*/, ... ] ( /*parameters*/ ) -> /*return type*/ in
// statements
}
...where /*reference type*/ can be either weak or unowned.
The capture list is the first thing to appear in the closure and it is optional. The syntax, as shown above is defined as one or more pairs of reference type followed by object; each pair is separated by a comma. For example:
[unowned self, weak otherObject]
Complete example:
var myClosure = {
[unowned self] in
print(self.description)
}
Note that an unowned reference is non-optional, so you don't need to unwrap it.
Hopefully that answers your question. You can read up more about ARC in Swift in the relevant section of the documentation.
You should pay particular attention to the difference between weak and unowned. It could be safer in your implementation to use weak, because using unowned assumes the object will never be nil. This may lead to your app crashing if the object has actually been deallocated before being used in your closure.
Using weak as the reference type, you should unwrap with ?, as follows:
var myClosure = {
[weak self] in
print(self?.description)
}

The only thing that threw me off with capture lists was when to use weak vs unowned.
The book distilled it down to these rules:
If self could be nil in the closure use [weak self].
If self will never be nil in the closure use [unowned self].
See the section Weak and Unowned References in The Swift Programming Language book for a deeper explanation.

As described above there are 2 possibilities to avoid retain cycles in Swift and these are weak and unowned as described below:
var sampleClosure = { [unowned self] in
self.doSomething()
}
where the self never can be nil.
var sampleClosure = { [weak self] in
self?.doSomething()
}
where self need to be unwrapped using ?.
Here there is a important observation to do, if there are more instructions that use self and can be share the results etc, a possible correct way can be:
var sampleClosure = { [weak self] in
if let this = self{
this.doSomething()
this.doOtherThings()
}
}
or
var sampleClosure = { [weak self] in
guard let strongSelf = self else{
return
}
strongSelf.doSomething()
strongSelf.doOtherThings()
}

Related

Why Swift don't automatically handle memory leaks?

When I started developing Swift code I wasn't that experienced handling memory leaks, so it take some time to me to figure out that what is a retain cycle, what is ARC, and why I should use weak or unowned inside my closures that was creating those retain cycles.
By default I always add this piece of code in closures that is referencing self:
class MyController: UIViewController {
var myClosure: (Data?, Error?)?
override viewDidLoad() {
self.myClosure = { [weak self] (data, err) in
guard let self = self else { return }
self.present(someVC, animated: true)
}
}
}
That code is something very common and using this weak modifier and also unwrapping self is something that is almost a default code.
That makes me question. If I have to always add a weak self in code that is referencing self and not allowing the class to be deinit WHY Apple don't make it a default behaviour on the language so we don't need to have this code repeating everywhere on our code base?
You don't have to always use weak self when referencing self in a closure.
But in this particular case you do have to and it was explained here

Captured weak reference pointed to wrong object

If I weakly reference self in a closure:
{[weak self] in self!.doSomethinmg()}
And self is deallocated, yet the closure continues to exist. Is it possible that self in the closure can become non-nil at some point in the future -- pointing to some random new object as determined by the runtime environment?
A pointer is a variable whose value is a memory address. The same is
true for a weak pointer, but the value of a weak pointer is
(due to some runtime magic) set to nil if the pointed-to object is
deallocated. It is irrelevant if any new object is created at the
same memory location later, the weak pointer variable stays nil.
So
{ [weak self] in /* ... */ }
creates a closure with a weak pointer variable. That variable
is set to nil when the pointed-to object is deallocated.
That may happen before the closure is called or during the execution
of the closure, so even
{ [weak self] in
if (self != nil) self!.doSomethinmg()
}
is unsafe and can crash if the object is deallocated between the test
and the method call.
But at any point, the weak pointer either points to
the original object instance or is nil. It will
never point to some other object instance. (That may happen with
unowned references.)
As Lorenzo says, don't
force unwrap the weak pointer. Either use optional chaining or
create a strong reference inside the closure.
It depends on what you want to achieve.
Martin is suggesting the right thing. In order to guarantee you don't have any crash and continue to deal with that instance you can use weak/strong dance. Otherwise, use self?.
So for example, with the weak/strong dance you can do the following:
{ [weak self] in
if let strongSelf = self {
strongSelf.doSomething()
}
}
Otherwise
{ [weak self] in
self?.doSomething()
}
While in the first case the instance that belongs to self will continue to exist until the closure will be discarded, in the second case, instead, since the instance will be put to nil, it will behave as a sort of non-op.
If all the strong references to an instance are removed, then the instance will eventually be deallocated. But that doesn't necessarily mean the references that were referring to it will be reused. All the strong references are obviously gone because they had to be in order for it to be deallocated in the first place. So whatever that means for the memory that those references required for their referring duties is irrelevant to the application, because the references don't exist anywhere in it anymore.
Which leaves unowned and weak references left. Apple makes it pretty clear that attempting to access the value of an unowned reference after the instance has been deallocated is a no, no:
If you try to access the value of an unowned reference after that instance has been deallocated, you’ll get a runtime error.
So that is also irrelevant to the application, simply because it's a hard-rule not to be broken.
Which leaves, last but not least, weak references. Apple says this about weak references:
Because a weak reference does not keep a strong hold on the instance
it refers to, it’s possible for that instance to be deallocated while
the weak reference is still referring to it. Therefore, ARC
automatically sets a weak reference to nil when the instance that it
refers to is deallocated.
...
You can check for the existence of a value in the weak reference, just
like any other optional value, and you will never end up with a
reference to an invalid instance that no longer exists.
The key take away here is that the reference is set to nil. And even though nil represents nothing, it's still a valid value. And I feel it may be safe to assume that the runtime environment won't steal a reference and use it for another purpose when it's still pointing to a valid value. Imagine what it'd be like otherwise.
So the relevance to the application here for weak references is just that they may become nil at some point; and as #MartinR showed in his answer, this may even happen mid-execution of the closure. So the final solution would seem to be creating a strong reference from the weak reference before using it, aka the "weak/strong dance":
Either:
{ [weak self] in
if let strongSelf = self {
strongSelf.doSomething()
}
}
or
{ [weak self] in
guard let strongSelf = self else { return }
strongSelf.doSomething()
}
If the closure consists of a single optional chain:
{ [weak self] in
self?.doSomething()
}
will simply result in a non-op if self is nil, but no idea if this bears any guarantee that self won't be deallocated mid-execution of the closure if it's arbitrarily longer:
{ [weak self] in
self?.doSomething()
...
self?.doSomethingDownTheLine()
}
So in this case, doing the weak/strong dance will guarantee that your closure will be all-or-nothing:
{ [weak self] in
guard let strongSelf = self else { return }
strongSelf.doSomething()
...
strongSelf.doSomethingDownTheLine()
}

When we should NOT use neither [weak self] nor [unowned self]?

I've read several discussion on StackOverflow about when we should use [weak self] or [unowned self] in closures.
However, are there any cases when we don't have to use neither of them since Swift doesn't show any error or warning when we're just explicitly using self inside a closure.
For example, should we use weak or unowned here?
UIView.animate(withDuration: 0.3) {
self.view.alpha = 0.0
}
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) />"
}
}
This is somewhat opinion based, so I'll give my opinion :)
I generally base it on synchronicity. If a closure is Async, the calling instance may no longer exist when the closer is called and therefore [weak self] should be used. If a closure is synchronous, it's unnecessary and capturing a strong reference is fine.
This could be expanded to also include closures where you can reasonably expect your instance to remain valid when it's called (e.g. your View animation case), however be aware this makes an assumption that the closure and your usage of it will remain unchanged, so it could theoretically break at some point in the future. This less safe and makes future maintenance more difficult/dangerous.
In the case of an established and predictable API like UIView.animate, I personally tend to use strong self for the sake of brevity, but that's an evaluation you'll need to do yourself and it depends on the usage.
Also as noted in the comments, this is true of function-closures. Assigning a closure to another variable's property has a different set of issues.
As an aside, I have adopted the approach of weak-reference closures simply calling another method in my Type, e.g.
thing.doSomethingWithAClosure() { [weak self]
self?.doSomething()
}
It simplifies the logic while also enforcing more functional/modular code.

Swift 3: capture strong self in #escaping closure without asynchronous work

There is a protocol with the following declaration:
typealias SuggestionSourceCallback = ([Suggestion]) -> ()
protocol SuggestionSource {
func suggest(_ query: SuggestionQuery, callback: #escaping SuggestionSourceCallback)
}
Two classes implement this protocol. First class obtains suggestions asynchronously (via GCD)
final class FisrtClass: SuggestionSource {
private let queue = DispatchQueue(label: "my.app.queue", attributes: [])
private var lastQuery: SuggestionQuery?
// ...
func suggest(_ query: SuggestionQuery, callback: #escaping SuggestionSourceCallback) {
self.queue.async { [weak self] in
// capturing strong self
guard let strongSelf = self else {
return
}
// referencing self here, for example
guard self.lastQuery == query else {
return
}
// suggestions is a local variable
var suggestions: [Suggestion] = []
// ...
DispatchQueue.main.async {
callback(suggestions)
}
}
}
}
...while second class does it synchronously
final class SecondClass: SuggestionSource {
// ...
func suggest(_ query: SuggestionQuery, callback: #escaping SuggestionSourceCallback) {
// ...
callback(self.suggestions[query])
}
}
My questions are:
should I capture strongSelf in FirstClass's implementation?
should I capture strongSelf in SecondsClass's implementation?
UPDATE
Additional question. Suppose SecondClass has its suggestions as a static let, what pattern in this case would be?
final class SecondClass: SuggestionSource {
static let suggestions: [String: [SuggestionQuery]] = {
// ...
}()
// ...
func suggest(_ query: SuggestionQuery, callback: #escaping SuggestionSourceCallback) {
// ...
callback(self.suggestions[query])
}
}
In SecondClass, there is no need to create a strongSelf variable. Where would you put it? The point is that self is guaranteed not to be nil anyway because you are running within the scope of one of its methods.
The same is true of your additional question, but for a different reason. suggestions is now static, so prefixing with self is a matter of syntax, (I am presuming you meant to also prefix the suggest method with static).
However, in FirstClass, there is a subtle difference between capturing strongSelf and not capturing it.
Because you are using [weak self], self could be nil when you enter that block so you need to check against that anyway. One way is to repeatedly use optional chaining, i.e.:
self?.doSomething()
self?.doSomethingElse()
This is saying:
If I have a reference to self, do something. If I still have a
reference to self, do something else.
By adding a strongSelf variable:
guard let strongSelf = self else {
return
}
strongSelf.doSomething()
strongSelf.doSomethingElse()
...you are saying:
do something and do something else if you have a reference to self,
otherwise do nothing.
So, you guarantee that if the first thing happens, so does the second. The approach you take is going to depend on your application.
Scenario 1 is a good candidate for [unowned self].
In this case if the queue exists, so does self, therefore it is safe to reference self without retaining it.
Note: You should only use unowned when you can be sure that the block's lifecycle is directly tied to the captured variable. In other cases unowned can cause interrmittent crashes (which are really hard to debug).
Also unowned is more performant than weak so should be preferred where it is safe to use either source.
For scenario 2, self is not captured by any block that I can determine so you shouldn't need to worry at all about it.
For the update, you still don't capture self, the closure that defines the suggestions dictionary should be executed as soon as it is called.

Referencing [weak self] as self? inside animateWithDuration causes crash

If I declare [weak self] on a closure and reference self as self? inside UIView.animateWithDuration the app will crash:
someFunc() { [weak self] (success) -> Void in
UIView.animateWithDuration(0.25) {
self?.someView.alpha = 1;
}
}
with a message sent to deallocated instance
but if I optionally unwrap self ahead of time it doesn't
someFunc() { [weak self] (success) -> Void in
if let weakself = self {
UIView.animateWithDuration(0.25) {
weakself.someView.alpha = 1;
}
}
}
Why is that, I would think that it doesn't matter which way I reference the weak self since it should "just" optionally unwrap self? correctly. For context this is done in a UICellView which is deallocated when I leave the UICollectionViewController
EDIT: Filed a bug with apple: #23492648
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.