Do We Need to Use _Weak Self Inside Uianimationblocks in Arc

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.

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?

Always pass weak reference of self into block in ARC?

It helps not to focus on the strong or weak part of the discussion. Instead focus on the cycle part.

A retain cycle is a loop that happens when Object A retains Object B, and Object B retains Object A. In that situation, if either object is released:

  • Object A won't be deallocated because Object B holds a reference to it.
  • But Object B won't ever be deallocated as long as Object A has a reference to it.
  • But Object A will never be deallocated because Object B holds a reference to it.
  • ad infinitum

Thus, those two objects will just hang around in memory for the life of the program even though they should, if everything were working properly, be deallocated.

So, what we're worried about is retain cycles, and there's nothing about blocks in and of themselves that create these cycles. This isn't a problem, for example:

[myArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){
[self doSomethingWithObject:obj];
}];

The block retains self, but self doesn't retain the block. If one or the other is released, no cycle is created and everything gets deallocated as it should.

Where you get into trouble is something like:

//In the interface:
@property (strong) void(^myBlock)(id obj, NSUInteger idx, BOOL *stop);

//In the implementation:
[self setMyBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[self doSomethingWithObj:obj];
}];

Now, your object (self) has an explicit strong reference to the block. And the block has an implicit strong reference to self. That's a cycle, and now neither object will be deallocated properly.

Because, in a situation like this, self by definition already has a strong reference to the block, it's usually easiest to resolve by making an explicitly weak reference to self for the block to use:

__weak MyObject *weakSelf = self;
[self setMyBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[weakSelf doSomethingWithObj:obj];
}];

But this should not be the default pattern you follow when dealing with blocks that call self! This should only be used to break what would otherwise be a retain cycle between self and the block. If you were to adopt this pattern everywhere, you'd run the risk of passing a block to something that got executed after self was deallocated.

//SUSPICIOUS EXAMPLE:
__weak MyObject *weakSelf = self;
[[SomeOtherObject alloc] initWithCompletion:^{
//By the time this gets called, "weakSelf" might be nil because it's not retained!
[weakSelf doSomething];
}];

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.

Referring to weak self inside a nested block

It depends.

You only create a retain cycle if you actually store the block (because self points to the block, and block points to self). If you don't intend to store either of the blocks, using the strong reference to self is good enough --- block will be released first after it got executed, and then it will release it's pointer to self.

In your particular example, unless you're performing more operations which are not shown, you don't need to create any weakerWeakerEvenWeakerSelfs.

Do methods called from within a block need to use weakSelf?

Retain cycle will be triggered only if you retain self inside the block. Otherwise it will just throw a warning only.

This is fine you can use this. Because block retains every vars used inside, so retain cycle would be like

  1. Self would retain block
  2. If block retains self then
  3. Self would again retain block
  4. block would retain self, so cycle goes on

The thing you are doing in method is just message passing. Everytime block is called a message would be sent to self to doSomething. And you can retain self in doSomething method it wont trigger retain cycle because this method dont have cycle loop to self. Hope you understand :)

  - (void)doSomething
{
self.myProperty = 5; // Is this ok or does it need to use a weakSelf?
}

substituting for __weak when not using ARC

You should not be worried about future versions of iOS because __weak is something interpreted by the compiler while producing code for you.

Looking at your other post suggests to me that your goal is to avoid weakOperation to be retained despite reference from within the block. In your specific case, where you don't use ARC, you can replace __weak by __block to indicate that your variable should not be retained during capture.

Note that the influence of__block on retain behavior is different between ARC and manual retain counting.

Should I use [weak self] in PromiseKit blocks?

That documentation is merely saying that you don't have to worry about PromiseKit introducing "strong reference cycles" (previously known as "retain cycles") because when the promise is fulfilled and the block finishes running, those strong references are automatically resolved for you. The choice of strong vs weak references is solely up to you.

For example, there's no need to keep a strong reference to a dismissed view controller if you are simply updating UI elements on scene that no longer exists. You'd use weak in that scenario. But sometimes you want strong reference (e.g. you may want to update the underlying model to reflect the success or failure of the promise).

Bottom line, all they're saying is that you shouldn't let PromiseKit dictate the strong vs weak references, but rather it should be driven by your app's broader design requirements. The only hard rule re PromiseKit is that you should avoid unowned.

Do I need to use a weak pointer when using C++ `function` blocks (as opposed to Objective C blocks)

C++ lambdas can captured variables either by value or by reference (you choose when you declare the lambda how to capture each variable).

Capturing by reference is not interesting, because references to local variables become invalid after you leave the variable's scope anyway, so there is no memory management issues at all.

Capturing by value: if the captured variable is an Objective-C object pointer type, then it gets interesting. If you are using MRC, nothing happens. If you are using ARC, then yes, the lambda "retains" captured variables of object pointer type, as long as they are __strong (not __weak or __unsafe_unretained). So, yes, it would create a retain cycle.



Related Topics



Leave a reply



Submit