6

I understand that the __block storage type is needed on scalar variables for the block to see updates to them, but when is it needed on objects? I believe __weak should be used when capturing a self reference to be used within the block, but I don't see when it would be necessary to actually use the __block storage type for ordinary objects.

chinabuffet
  • 5,278
  • 9
  • 40
  • 64
  • Also [what the difference between __weak and __block reference?](http://stackoverflow.com/questions/11773342/what-the-difference-between-weak-and-block-reference) – Dave FN Jul 24 '13 at 00:26
  • I'm specifically asking: when the `__block` storage type should be used on non-scalar, non-self object references when using ARC? If those other links answer that question I've missed it. – chinabuffet Jul 24 '13 at 00:30
  • @chinabuffet: There is no difference between how it works for scalar types and object pointer types. – newacct Jul 24 '13 at 21:16

2 Answers2

17

__block is needed for scalar variables if you want to change their value with code inside the block. Captured scalars appear as const inside the block and therefore cannot be changed. If you have a pointer to an object, the same distinction applies--the captured pointer itself will be a const pointer and therefore cannot be modified, but the object pointed to can be modified by code inside the block. If you want to change the object pointed to, then the pointer itself must change, and so the pointer must be declared with the __block type. It is never necessary to declare the object itself as __block, but only the pointer to the object, and only if the pointer must be changed.

If you have the right mental model, blocks aren't that confusing. It is important to know that blocks are initially allocated on the stack, and so vanish when the lexical scope is destroyed as the stack frame is popped. If you want the block to hang around past the lifetime of the lexical scope in which the block was created, move it to the heap using Block_copy() or sending it a -copy message. When a block is copied to the heap, all the captured const variables go along, and any objects these const variables point to are retained. When the block is removed from the heap, all objects pointed to by the const variables are released.

__block variables "under the hood" have an extra layer of indirection the compiler uses (and that you don't see) included in the block, so when the block is copied to the heap, so are the captured __block variables, and the invisible pointers are adjusted to point to the new heap location of these __block variables. This means the address of a __block variable can change, so be careful if you use that address. You can also see that a __block variable lives 'outside' the block in some sense, so these variables can be read and modified from code external to the block.

I've been brief, but you can find better explanations here, listed in increasing complexity:

http://ios-blog.co.uk/tutorials/programming-with-blocks-an-overview/

http://www.cocoawithlove.com/2009/10/how-blocks-are-implemented-and.html

http://www.mikeash.com/pyblog/friday-qa-2011-06-03-objective-c-blocks-vs-c0x-lambdas-fight.html

Fred
  • 8,582
  • 1
  • 21
  • 27
  • So if the block is passed as a reference somewhere, does whatever is receiving that block as a parameter need to immediately copy the block in order to use it in the future? – chinabuffet Jul 24 '13 at 12:27
  • If the block reference can outlive the lexical scope (stack frame) in which the block was defined, it must be copied to move the block object to the heap. I'd think it would be safer to do the copy when creating the block than to have these copies occurring at places remote from the creation. – Fred Jul 25 '13 at 03:48
  • is `__block` needed in the forin loop of objc? – Developer Sheldon Apr 29 '20 at 18:49
0

They are used for function level variables. These are mutable within the block (and the enclosing scope) and are preserved if any referencing block is copied to the heap. Variables local to the enclosing lexical scope declared with the __block storage modifier are provided by reference and so are mutable. Any changes are reflected in the enclosing lexical scope, including any other blocks defined within the same enclosing lexical scope.

__block variables live in storage that is shared between the lexical scope of the variable and all blocks and block copies declared or created within the variable’s lexical scope. Thus, the storage will survive the destruction of the stack frame if any copies of the blocks declared within the frame survive beyond the end of the frame (for example, by being enqueued somewhere for later execution). So use them when you need to modify the object within a block or when you will need the object after the destruction of the stack frame.

random
  • 8,568
  • 12
  • 50
  • 85