__block Variables and Objects
The __block specifier can be used for any type of automatic variable. Let’s see how it is used for an id-type automatic variable to assign an Objective-C object.
__block id obj = [[NSObject alloc] init];
This is equivalent to:
__block id __strong obj = [[NSObject alloc] init];
When ARC is enabled, variables of id or an object type always have ownership qualifiers, and __strong is used as its default. It is converted by clang as follows.
/* struct for __block variable */
struct __Block_byref_obj_0 {
void *__isa;
__Block_byref_obj_0 *__forwarding;
int __flags;
int __size;
void (*__Block_byref_id_object_copy)(void*, void*);
void (*__Block_byref_id_object_dispose)(void*);
__strong id obj;
};
static void __Block_byref_id_object_copy_131(void *dst, void *src) {
_Block_object_assign((char*)dst + 40, *(void * *) ((char*)src + 40), 131);
}
static void __Block_byref_id_object_dispose_131(void *src) {
_Block_object_dispose(*(void * *) ((char*)src + 40), 131);
}
/* __block variable declaration */
__Block_byref_obj_0 obj = {
0,
&obj,
0x2000000,
sizeof(__Block_byref_obj_0),
__Block_byref_id_object_copy_131,
__Block_byref_id_object_dispose_131,
[[NSObject alloc] init]
};
_Block_object_assign and _Block_object_dispose functions, which are explained in the previous section, are used.
When an automatic variable of id or object type is captured for a Block and the Block is copied from the stack to the heap, the _Block_object_assign function is called so that the Block takes ownership of the captured object. When the block on the heap is disposed of, the _Block_object_dispose function is called to release the captured object.
When an automatic variable of id or object type with a __strong qualifier has a __block specifier, the same thing happens. When the __block variable is copied from the stack to the heap, a _Block_object_assign function is called so that the Block takes ownership of the __block variable. When the __block variable on the heap is disposed of, the _Block_object_dispose function is called to release the object in the __block variable.
Now we understand that as long as the object type __block variable with a __strong qualifier exists on the heap, the object, which is assigned to the __block variable, exists as well and ownership of it is managed properly. It is just like an object, which is assigned to the object type automatic variable with a __strong qualifier, is used inside a Block.
By the way, for now, we’ve learned only about automatic variables of id or object type with a __strong qualifier. How about other ownership qualifiers? What will happen with __weak ownership qualifiers? The next source code is about id type variables with a __weak qualifier.
blk_t blk;
{
id array = [[NSMutableArray alloc] init];
id __weak array2 = array;
blk = [^(id obj) {
[array2 addObject:obj];
NSLog(@"array2 count = %ld", [array2 count]);
} copy];
}
blk([[NSObject alloc] init]);
blk([[NSObject alloc] init]);
blk([[NSObject alloc] init]);
The result is different from the result in the section, "“Capturing Objects.”
array2 count = 0
array2 count = 0
array2 count = 0
This is because the variable “array” is released and discarded when the variable scope is left, and nil is assigned to the variable “array2”. It just works as expected.
What will happen when the __block specifier and __weak ownership qualifier are used at the same time?
blk_t blk;
{
id array = [[NSMutableArray alloc] init];
__block id __weak array2 = array;
blk = [^(id obj) {
[array2 addObject:obj];
NSLog(@"array2 count = %ld", [array2 count]);
} copy];
}
blk([[NSObject alloc] init]);
blk([[NSObject alloc] init]);
blk([[NSObject alloc] init]);
The result is same as the previous one.
array2 count = 0
array2 count = 0
array2 count = 0
Even with __block specifier, when the variable scope is left, the variable “array” with a __strong qualifier is released and discarded, and then nil is assigned to the variable “array2” because “array2” is qualified with __weak.
A variable with a__unsafe_unretained qualifier is just same as a simple pointer. No matter how it is used, inside a Block or with a __block specifier, no mechanism for a __strong or __weak qualifier works. So, when you use a variable with __unsafe_unretained qualifier, please take care not to access a discarded object through the dangling pointer. Please seeChapter 2, the “__unsafe_unretained ownership qualifier” section.
The __autoreleasing qualifier is not assumed to be used with a Block, and so it should not be used. If you use it with __block specifier, a compiling error occurs.
Because the __autoreleasing ownership qualifier and __block specifier are used for the variable “obj”, a compiling error occurs:
error: __block variables cannot have __autoreleasing ownership
__block id __autoreleasing obj = [[NSObject alloc] init];