Is It Necessary to Use [Unowned Self] in Closures of Uiview.Animatewithduration(...)

Is it necessary to use [unowned self] in closures of UIView.animateWithDuration(...)?

No, it is not needed in this case. animations and completion are not retained by self so there is no risk of strong retain cycle.

UIView.animate() : do I need a weak reference to self in the animation block?

Sure, you do need to use the "weak self" concept there.

In fact note: it is indeed very common in that situation that a VC is trashed during an animation ... so indeed, it's one of the places you "most need" to use the weak-self idea. It's a very common mistake in projects to forget that in an animation.

By the way, here's a handy syntax any time you need weak self:

func animate() {
UIView.animate(withDuration: 0.3, animations: { [weak self] in
guard let self = self else { return print("gotchya!") }
self.label.alpha = 0.5
}) { [weak self] in
guard let self = self else { return print("gotchya!") }
self.animate()
}
}

Adding this line ..

        guard let self = self else { return }

.. can seem a bit long-winded, but, it means you then don't need the "?"
after "self" every time you use it in long blocks.

Often you will have many uses of "self ..." inside such a block, and it seems more consistent to just use the "let self = self" idiom.

Sample Image

So even if there is only one line of code in the block (as in your two examples) it's a good way to be absolutely consistent everywhere and keep things simple.

Note that whenever you have a { return } you can just add a print statement so that you know what is going on during development ..

.... { [weak self] in
guard let self = self else { return print("I avoided a crash, woot!") }

or

.... { [weak self] in
guard let self = self else { return print("logical disaster near line 66") }

You do not have to do that, "{ return }" is fine. It's just for your convenience.

What the hell is this "self = self" business?

If you find the "self = self" idiom confusing ....... honestly, just don't worry about it. Always use that idiom. It's really just the "standard" thing you will see everywhere.

Always go for simple consistency in your code base!

More weak self mysteries ...

Here's a interesting QA from a handsome list member: Where does the weak self go?

And later there's this sort of confusion to worry about: What is the difference between a weak reference and an unowned reference?

Do I need [unowned self] or [weak self] in this closure?

In this case you don't need to use capture list, because both closures are UIView and not retained by self. The retain cycle is not created in your example.

Do we need to use __weak self inside UIAnimationBlocks in ARC?

This is not a retain cycle. A retain cycle would be

self -> block -> self

In this case we have

animation framework -> block
block -> self

where the first retain is only temporary - the block gets released when the animation ends. Even if a retain cycle happens, it will be only temporary and it won't prevent object deallocation.

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

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.

Use [weak self] in the nested block in swift

If you don't use [weak self], then for the life time of that block, you can have a circular reference between it and the object self refers to, when an object loses a reference to it, its reference drops by one, when it reaches zero then it is deallocates and reduces the reference count of any object it has a reference to. If you have a circular reference then neither are going to reach zero, because neither is going to get to zero to deallocate itself and reduce the reference to the other. For regular objects this is a problem because they will never be deallocated, for block though, it can depend on how they are used, if they are passed to a function that uses them straight away, then once they are executed they will be deallocated, and any circular references will be cut, it may be even beneficial that whilst your block is executing that it and self can't go away, but if the block is retained as an instance variable to be called, then you have a circular reference that will never go away. The way to deal with is is to use [weak self], saying references to self are weak in this block, you can then just deal with that on each time you use it, self?.myFunction() for example, or you can create a strong reference at the beginning, it used to be you used to have to use a different variable to self, but now you can go

guard let self = self else { return }

one of the good things of doing it this way, you are saying if it gets this far I want the block to execute completely, you have created a circular reference for the execution of the block and it will not go away until the block finishes executing. For example if you have a few functions starting with self?, then mid way through your block executing self could become nil, and only the first few functions are executed and the later are not.

Swift UIView animateWithDuration completion closure called immediately

I resolved this in the end by moving the animation from hitTest() and into touchesBegan() in the UIView

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) />"
}
}


Related Topics



Leave a reply



Submit