0
votes

I saw a solution to preventing block retain cycles here

But I am having trouble wrapping my head around why or even how it works.

In the example, a weak self reference is made and acted upon. I can see how this Breaks the cycle. However, within the block a strong reference is created. Wouldn't this recreate the retain cycle that we were trying to prevent in the first place?

Let's say for example that self is 0x123 Then weakself is also pointing to 0x123. Then strongSelf would get set to 0x123 inside the block.
Wouldn't this make a retain cycle?(self has strong reference to block and strongSelf has a strong reference to self)

2

2 Answers

1
votes

Let's say for example that self is 0x123 Then weakself is also pointing to 0x123. Then strongSelf would get set to 0x123 inside the block. Wouldn't this make a retain cycle?

Actually, no; they do not all point directly at the same thing. The fact is that an ARC weak reference really does (behind the scenes) interpose an extra object into the mix. Let's call it a scratchpad object. It gives the illusion that we are pointing at the same object, but we are actually pointing through the scratchpad object, which does not retain the thing it points to. That's how ARC weak references work (also known as zeroing weak references); they involve special extra go-between scratchpad objects that can be retained without themselves retaining, thus breaking the chain.

In a retain cycle, A has a retain on B and B has a retain on A. Each will put a release on the other in its own dealloc, but that moment will never come.

In the block situation, A is self and B is the block. self put a retain on the block for whatever reason it did so (often rather obscure, having to do with copying, observers, etc.; it doesn't always happen, and in fact it happens much more rarely than most people seem to suppose). The block put a retain on self merely by virtue of the fact that it is a closure and self is referred to with in the block.

But by doing the weak-strong dance, we prevent this. What passes into the block is weakself, which is actually a reference through the scratchpad object. The block can retain this, but it, in turn, does not retain self. Hence there is no retain cycle.

1
votes

Within the block a strong reference is created. Wouldn't this recreate the retain cycle that we were trying to prevent in the first place?

Yes, it does, but only temporarily. When strongSelf is initialized, it forms a strong reference to the current weakSelf value. (Or nil, if that object has been deallocated.) Once the block finishes running, this (local) strong reference will be released, breaking the cycle.

The problem is not a retain cycle per se (they happen all the time), but a long-lived retain cycle that keeps its objects alive for longer than expected.