0

The common pattern to avoid capturing self within a Block is to create a weak self outside the Block and use this to create a "locally strong" version of self within the Block (inner self).

__weak ClassX *weakSelf = self;
[someOtherObject methodThatTakesCOmpletionBlock: ^{

             ClassX innserSelf = weakSelf; //innserSelf creation?     
             [someObject send:innerSelf.prop;}];

What happens when the innserSelf creation line is executed? Is innerSelf a copy of self at the time the method methodThatTakesCompletionBlock: is sent to someOtherObject?

This question just focusses on what happens when the innserSelf line is executed. I've seen Strong reference to a weak references inside blocks which is related but doesn't address this point.

Community
  • 1
  • 1
Smart Home
  • 801
  • 7
  • 26
  • @Josh Caswell The answers don't address one of my questions. What happens when the `ClassX innserSelf = weakSelf;` line is executed. Does it copy self object and keeps a reference of it. I edited my question to only have this. Can you please remove tend plicate flag? – Smart Home Oct 08 '16 at 23:49
  • No pointer assignment creates a copy of the object. – jscs Oct 09 '16 at 00:01
  • What do you mean by "No pointer assignment creates a copy?" Did you want to say "Pointer assignment does **not** create a copy?" If it does not create a copy, then what is the whole point of this inner self thing. It looks like we still have a strong reference to the "piece of memory" pointed by self. – Smart Home Oct 09 '16 at 00:02
  • Sure, it can be phrased that way as well. – jscs Oct 09 '16 at 00:04
  • Sorry, your answers are too cryptic for me! If it does not create a copy, then what is the whole point of this inner self thing. It looks like we still have a strong reference to the "piece of memory" pointed by self. – Smart Home Oct 09 '16 at 00:05
  • The point is clearly explained in the duplicate I pointed you at... – jscs Oct 09 '16 at 02:57
  • When I read all the posts related to the topic, it appears that my code will not create a retain cycle even if I don't use the weakSelf, innerSelf thing. This is because I am just handing off the block to another object to execute. I am not storing it in a property of self. Is that correct understanding? – Smart Home Oct 09 '16 at 17:29
  • Correct: if `someOtherObject` is not owned by `self` and/or `someOtherObject` does not own the Block, then there is no retain cycle from referring to `self` inside the Block. – jscs Oct 09 '16 at 18:08
  • Thanks @JoshCaswell. Even if someOtherObject is owned by self and i someOtherObject stores the block in a property, it appears that things will sort themselves out when self releases someOtherObject. The thing which is broken is if the entity holding a reference to self, releases self, then we won't get the deallocation chain anymore. Is that a correct understanding? – Smart Home Oct 09 '16 at 18:22

2 Answers2

3

Consider:

 __weak id weakSelf = self;
 [other doSomething: ^{
     __strong id strongSelf = weakSelf;
     ....
 }];

When other copies the block, there is no strong reference.

When other executes the block, then the strong reference is created at the beginning of the block's execution. When the block is done, the execution scope is gone and, thus, the strongSelf reference is destroyed.

Whether other hangs onto the block or not is irrelevant; the strongSelf reference only exists during block execution.

bbum
  • 162,346
  • 23
  • 271
  • 359
  • Thanks @bbum. What happens if self gets de-allocated by the time block executes? Then strongSelf will be nil, is that correct understanding? My question about `other` storing the block was to find out under what situation is not going through weak/self dance dangerous. I see the only problem is if other has a property to store the block. If it just executes it, it looks like going "straight" self instead of inner self is better. This way self is guaranteed to exist when block executes. When it is done, the block will release its strong reference, breaking the cycle. Thoughts? – Smart Home Oct 10 '16 at 01:22
  • @SmartHome Correct; `strongSelf` will be nil. You can test it on the next line and short circuit the block, if you want. Under ARC, the weak/strong assignment mechanism is atomic; you want get an invalid `strongSelf`. – bbum Oct 10 '16 at 01:24
  • 2
    The danger is if the block is never executed. If you do anything where you require the block to be executed to break the cycle, you run the risk of never breaking the cycle if the block isn't executed. By exposing whether or not `other` delays execution or does direct execution and then relying on that in the caller, you are exposing an implementation detail that will make refactoring difficult and error prone. The self -> weakSelf -> strongSelf dance isn't error prone beyond adding more noise in the code. – bbum Oct 10 '16 at 16:01
0

Assigning a weak pointer to a strong one does not copy the object. Both pointers will point to the same object. The strong pointer retains thus adding +1 to the retain count. The weak pointer does not alter the retain count

  • Thanks. In that case, don't we once again have a reference cycle? block has a strong reference to self (through innersole) and self has a string reference to block. What is the difference between this and directly using self within the block? – Smart Home Oct 09 '16 at 01:37
  • 1
    The reference cycle only exists when the block is executing. Which is likely desirable. – bbum Oct 09 '16 at 02:43
  • @bbum, Thanks. When I read all the posts related to the topic, it appears that my code above will not create a retain cycle even if I don't use the weakSelf, innerSelf dance. This is because I am just handing off the block to another object to execute. I am not storing it in a property of self. Is that correct understanding? – Smart Home Oct 09 '16 at 17:29
  • @SmartHome In your example, there are two phases. `someOtherObject` stores the block-- phase one-- and if that block has a strong reference to self which has a strong reference to someOtherObject, a reference cycle is created. During the execution phase-- phase two-- that reference cycle is likely desired because it means that the block's task will complete as expected. Once the block is done executing, the phase two reference cycle is destroyed when the strong reference to self in the block goes out of scope. – bbum Oct 09 '16 at 18:39
  • Thanks @bbum. In your example above, it looks like the retain cycle won't go away even after block executes if someOtherObject stores the block in a property & block captures self without the weakSelf/innerSelf dance. I.e self has someOtherObject in property, someOtherObject holds block in a property and block captures self without the weakSelf/innerSelf dance. In this case, since someOtherObject is storing the block in a property, the reference cycle goes away only after someOtherObject sets this property to nil (i.e not after block executes). This seems to be only reason for the dance. – Smart Home Oct 09 '16 at 19:13
  • @SmartHome: "block has a strong reference to self (through innersole)" No. `innserSelf` is a local variable. The block does not have a strong reference to `self`. – newacct Oct 10 '16 at 21:57
  • @SmartHome: "it appears that my code above will not create a retain cycle even if I don't use the weakSelf, innerSelf dance. This is because I am just handing off the block to another object to execute. I am not storing it in a property of self. Is that correct understanding?" What is the variable `someOtherObject`? A local variable? Or an instance variable? If an instance variable, that implies that `self` has a strong reference to that object. If an local variable, and `self` does not otherwise have a reference to it, yes, that is correct. – newacct Oct 10 '16 at 21:59