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

Viewed 7535

After some research I found out my app was using way too much energy because of several UIView animations throughout the app, where I was capturing the related UIViewController in the completion block, without making a weak reference to it.

So actually, I changed this:

func animate() {
    UIView.animate(withDuration: 0.3, animations: {
        self.label.alpha = 0.5
    }) { _ in 
        self.animate()
    }
}

Into this :

func animate() {
    UIView.animate(withDuration: 0.3, animations: {
        self.label.alpha = 0.5
    }) { [weak self] _ in 
        self?.animate()
    }
}

However, I would like to know if I need to do the same with the animation block (the self.label.alpha = 0.5 one) ?

Thank you for your help

4 Answers

You don't need to use [weak self] in static function UIView.animate() You need to use weak when retain cycle is possible and animations block is not retained by self.

There is an article on medium about where [weak self] may and may not be needed

For more information:

There might be another issue for the energy problem.

What do you mean by:

my app was using way too much energy

I don't see any immediate relation between keeping a weak reference on your view controller and saving energy. Capturing self without increasing its retain count in your closure (that's what we mean by having a weak reference on an object) means that if no other strong reference on your view controller exists, then your view controller will be released sooner. Maybe you will save some RAM in a very short term.

I would suggest to investigate somewhere else to find where your "energy" issue comes from.

There are a lot of articles about the use of weak keyword.

https://medium.com/flawless-app-stories/you-dont-always-need-weak-self-a778bec505ef

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.

enter image description here

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?

Related