Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are __block variables not retained (In non-ARC environments)?

I was reading through the documentation on __block variables, and thinking about the cases where I use __block. To me, it seems like I need it in two cases:

  • To mark a variable as read-write when used within a block
  • To avoid retain cycles when referencing self within a block

On the surface it doesn't seem like these two things are related. I consider the fact that __block variables not being retained as more of a trick I need to remember for the specific use case of avoiding retain cycles.

I'm wondering, is there a more important, architectural reason why they must not be retained? I would think some other keyword to indicate this might be more clear, as to not mix up the two features listed above.

update -

I should mention this is code that does not use ARC. I now see that __block variables are in fact retained in ARC.

like image 522
D.C. Avatar asked Jun 29 '13 20:06

D.C.


1 Answers

__block variables are not retained if you use Manual Reference Counting. The reason can be found here: http://www.mikeash.com/pyblog/friday-qa-2009-08-14-practical-blocks.html:

A simple workaround to this lies in the fact that __block variables are not retained. This is because such variables are mutable, and automatic memory management of them would require each mutation to generate memory management code behind the scenes. This was seen as too intrusive and difficult to get right, especially since the same block may be executing from multiple threads simultaneously.

and also here: http://lists.apple.com/archives/objc-language/2009/Dec/msg00100.html

There is no way to properly and efficiently manage the retain counts upon re-assignment of the value within the variable.

(I could not find an "official" reference in the Apple documentation.)

As documented in the "Transitioning to ARC Release Notes", this behavior changed with ARC:

In manual reference counting mode, __block id x; has the effect of not retaining x. In ARC mode, __block id x; defaults to retaining x (just like all other values). To get the manual reference counting mode behavior under ARC, you could use __unsafe_unretained __block id x;. As the name __unsafe_unretained implies, however, having a non-retained variable is dangerous (because it can dangle) and is therefore discouraged. Two better options are to either use __weak (if you don’t need to support iOS 4 or OS X v10.6), or set the __block value to nil to break the retain cycle.

like image 139
Martin R Avatar answered Oct 17 '22 00:10

Martin R