What happens when you create a block?
Normally when you write a block in Objective C, the compiler actually creates an Objective C object, however the object is likely different to any other Objective C object that you will have seen. One of two types of block will be created:
If the block doesn’t use any variables from outside its scope a global block will be created. In concept this works exactly the same as a nameless function; it’s an area of code that you can call into and is always there, it never gets destroyed. If you were to save the address of this block when creating it you could call into this code at any time during the lifetime of your program. As you don’t reference any variables from outside the block, there are no issues with memory management. These blocks are not interesting from a memory management point of view, so will be mostly ignored in the rest of the blog post.
If the block references any variables that are declared outside the block then the block will be created as a stack object. This isn’t something that exists in the rest of the Objective C world. The rest of the time when you create an object, memory is put on the heap, not the stack (other languages do support stack objects as a normal concept).
The block being a stack object has some nice advantages. It’s always really fast to create the object; the program’s stack is calculated in advance so there is no need to do any work to find contiguous memory to allocate for the object, it’s already there. The second (and more important) is that all of the object’s memory drops off the stack once you leave the current stack frame, i.e. when you return from your function or method. This means that in a manual reference counted (MRC) environment you can create the block object without having to keep a reference to it to manually free its memory, i.e. you can do this:
1 2 3 4 5
We don’t need to worry about the object that this has secretly created because all of that object’s memory will be cleared once we leave the function.
This is very different to other objects on the heap. In an MRC environment the following will cause you to leak memory:
We have created an
NSView but have no way to release it again. To solve this
we would need to do the following:
1 2 3
So by making blocks secretly stack objects, they can work nicely with manual reference counting with a nice syntax where we appear to be just adding a block of code as an argument.
Another important thing to note is that because blocks are secretly
stack objects, they can’t take ownership (i.e. increment the retain count)
of any variables used inside the block that were declared outside the block
(well at least not without the magic of ARC).
The block objects aren’t deallocated; their memory is simply dropped when
the method returns, so under MRC there is nowhere where the block could
remove its ownership of the objects (which would normally be done in
dealloc). This means that code like this:
1 2 3 4 5 6 7
may cause a crash as the array object has been deallocated.
(If you’re very unlucky the
array pointer will point at
something that responds to the
description method and you
won’t get the crash.)
As the block is on the stack, keeping a reference to the block that outlasts the scope of the function/method won’t work:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
The above code causes a crash (without the reference to
within the block, a global block is created, so everything would
If you want to keep a block around outside of your method
you need to call the
copy method on the block. This method
will copy the block from the stack to the heap. It will also
retain all of the variables that the block references. This
means that the block now owns the variables that are referenced
inside the block. So if we change the block ownership code example
a couple above then we won’t crash:
1 2 3 4 5 6 7 8 9 10 11
There are a couple of things to note here. We need to keep
a reference to our copied block; this block is now under the
normal reference counting rules and we need to release it
when appropriate. The variables declared outside the block
that are used within the block have also had their retain
counts incremented, so when we call
blockCpy after releasing
array we don’t crash.
What changes in ARC?
In ARC the memory management works differently. Suddenly
with ARC there is the magical ability to deallocate the instance
variables of the block when the block drops out of scope.
This means that the block can have strong instance
variables (i.e. it can increment the
its instance variables) without the risk of leaking memory.
When you create a block in ARC the block’s instance variables
(the variables that were declared outside the block,
and used inside the block) are declared with the
same ARC Ownership Qualifiers as they were declared
with outside of the block. This means that if you
use a variable that is declared as
a block, the block will keep a
__strong copy of the
variable (i.e. the variable’s
retainCount will be
incremented). If however the variable’s ownership
retainCount won’t be incremented by the block
(you can’t capture an
__autoreleasing variable in a block).
Here is code similar to the Block Ownership code
from earlier, and it won’t crash:
1 2 3 4 5 6 7
The block has kept a reference to
Let’s instead try passing in a
1 2 3 4 5 6 7 8
This code will print
(null) to the console. This is
because when the object referenced by a
is deallocated the
__weak variables associated with the
object are set to
nil. In this case when we do
array = nil,
wkArray is set to
If instead we gave
wkArray an ownership qualifier of
__unsafe_unretained we’d likely get a crash
(we’d definitely get a crash if Zombies are enabled).
This is because
wkArray now points to the location
of an object that has been deallocated, and
doesn’t have the magic ability of
__weak to make the
nil when it is deallocated.
In some instances you may be thinking that your code should
always have a reference to the variable that you have
used in a block in a non-
__strong way (i.e. you know that
__strong reference to the object exists when you
call the block) and that you’d rather have a crash if there
is no reference to the object. In this case I’d recommend
__weak and asserting that the variable exists
within the block, as using
guarantee you will have a crash when you try and reference
This makes the ARC situation with blocks very different to the
MRC situation. When you use a
__weak reference within
a block it doesn’t matter if the block is on the stack or the
heap, the block won’t take ownership of the object. Conversely if
you use a
__strong reference regardless of whether the block is
on the heap or the stack the block will take ownership of the object.
The ability to use
__weak references within a block allow you to
avoid retain cycles. The following code will never cause a retain
1 2 3 4 5 6 7 8 9 10 11 12 13 14
If the block kept a
__stong reference to
self here, we
would have a retain cycle.
However, because the block doesn’t keep a strong reference
JTAObject, if something else has a reference to the
block it’s possible for the block to be called after
has been deallocated. If this is a possibility in your code,
due to the magic of weak references you can check whether
weakSelf exists and exit the block early if it doesn’t.
The above applies regardless of whether the block is on the stack or the heap. The memory management is done entirely based on the ownership qualifiers of the objects referenced within the block.
It doesn’t really matter any longer whether a block is on the stack or the heap as ARC will clear things up anyway. It is however interesting to know what types of blocks we are creating:
If you create a block and no variables are referenced within the block, then a global block is created and all reference counting (including ARC) is ignored. The following options assume that you reference a variable from outside the block.
If you create a block and don’t keep a reference to the block (i.e. you pass it into a method immediately) then a stack block will be created.
If you create a block and keep a
__strongreference to the block (which is the default) the block will be immediately copied to the stack so that ARC can deallocate the block sensibly when it goes out of scope.
If you create a block and keep an
__unsafe_unretainedreference then the block will be created on the stack like it is in MRC.
If you try to create a block and only keep a
__weakreference to it, the block will be moved to the heap and immediately deallocated, probably causing a crash. So this is a very bad idea.
If you’re interested can test the type of block you have by printing the
class block in the debugger (i.e.
po [myBlock class]). Global blocks have
__NSGlobalBlock__, blocks on the heap have a class of
__NSMallocBlock and blocks on the stack have a class of