16

I've recently come across an Apple document that shows the following property declaration for a block:

@interface XYZObject : NSObject
@property (copy) void (^blockProperty)(void);
@end

Also, this article states:

Note: You should specify copy as the property attribute, because a block needs to be copied to keep track of its captured state outside of the original scope. This isn’t something you need to worry about when using Automatic Reference Counting, as it will happen automatically, but it’s best practice for the property attribute to show the resultant behavior. For more information, see Blocks Programming Topics.

I also read the suggested Blocks Programming Topics but haven't found anything relevant there.

I'm still curious as to why defining a block property as "copy" is best practice. If you have a good answer, please try to distinguish between ARC and MRC differences if there are any.

Thank you

Stavash
  • 14,244
  • 5
  • 52
  • 80
  • NB, for beginners who are just wondering how the hell to use a block :) http://stackoverflow.com/a/20760583/294884 – Fattie Mar 21 '15 at 05:34

3 Answers3

25

By default blocks are created on the stack. Meaning they only exist in the scope they have been created in.

In case you want to access them later they have to be copied to the heap by sending a copy message to the block object. ARC will do this for you as soon as it detects a block needs to be accessed outside the scope its created in. As a best practise you declare any block property as copy because that's the way it should be under automatic memory management.

Read Stack and Heap Objects in Objective-C by Mike Ash for more info on stack vs. heap.

Joris Kluivers
  • 11,894
  • 2
  • 48
  • 47
  • Shouldn't they also be declared as week, in case you capture self and create a retain cycle? – cfischer Feb 19 '14 at 17:43
  • Absolutely not, because most of the time the property would be the only reference to the block, so if the property was weak, the block would disappear immediately. – gnasher729 Mar 18 '14 at 23:54
  • Hi Joris. To be absolutely clear, in fact if you simply **omit** the Copy, are you saying in fact it will, anyway, be copied? Again to be absolutely clear, in fact is it the case that if you completely omit the copy, versus having a copy, actually the result, handling and execution will be completely identical? Cheers.. – Fattie Mar 21 '15 at 05:40
7

Blocks are, by default, allocated on the stack. This is an optimization, since stack allocation is much cheaper than heap allocation. Stack allocation means that, by default again, a block will cease to exist when the scope in which it is declared exits. So a block property with retain semantics will result in a dangling pointer to a block that doesn't exist anymore.

To move a block from the stack to the heap (and thus give it normal Objective-C memory management semantics and an extended lifetime), you must copy the block via [theBlock copy], Block_copy(theBlock), etc. Once on the heap, the block's lifetime can be managed as needed by retaining/releasing it. (Yes, this applies in ARC too, you just don't have to call -retain/-release yourself.)

So you want to declare block properties with copy semantics so the block is copied when the property is set, avoiding a dangling pointer to a stack-based block.

Jonathan Grynspan
  • 43,286
  • 8
  • 74
  • 104
  • However, the two answers above seem to imply this must be done, and is anyway done, automatically, by ARC - and the **sole reason** for including copy explicitly, is stylistic -- "to remind everyone" that is what is actually happening. Thoughts?? – Fattie Mar 21 '15 at 05:42
6

The "best practices" you refer to simply say, "Seeing as ARC is going to magically copy your block no matter what you write here, it's best you explicitly write 'copy' so as not to confuse future generations looking at your code."

Explanation follows:

Typically, you shouldn’t need to copy (or retain) a block. You only need to make a copy when you expect the block to be used after destruction of the scope within which it was declared. Copying moves a block to the heap.
–Blocks Programming Topics: Using Blocks, Copying Blocks

Clearly, assigning a block to a property means it could be used after the scope it was declared in has been destroyed. Thus, according to Blocks Programming Topics that block should be copied to the heap with Block_copy.

But ARC takes care of this for you:

Blocks “just work” when you pass blocks up the stack in ARC mode, such as in a return. You don’t have to call Block Copy any more.
Transitioning to ARC

Note that this isn't about the retain semantics the block. There's simply no way for the block's context to exist without being moved off the (soon-to-be-popped) stack and on to the heap. So regardless of what attributes you qualify your @property with, ARC is still going to copy the block.

jemmons
  • 18,605
  • 8
  • 55
  • 84
  • In case anyone is worried about efficiency or functionality, once a block has been copied, the result is immutable and further attempts to copy will just retain it, like other immutable instances. – gnasher729 Mar 18 '14 at 23:56
  • Hi jenmore. thanks for the post. As I asked above, what is your opinion ... "to be absolutely clear, in fact is it the case that if you completely omit the copy, versus having a copy, actually the result, handling and execution will be completely identical??" What do we reckon? Cheers! – Fattie Mar 21 '15 at 05:41