You can read this article with the following questions
Basic questions
- What is Block? Please give an example of Block usage scenarios.
- How does Block capture external variables? Please explain the rules for Block capture variables.
- Please explain Block memory management, especially the difference between non-ARC and ARC environments.
Advanced questions
__block
What do modifiers do? What are the precautions for using it?- Please explain the three types of Blocks and their characteristics.
Advanced questions
- Please explain the underlying implementation principle of Block, including how to copy from stack to heap.
__forwarding
What is the role of pointers? How does it support__block
memory management of variables?- Why should we design __block, __frowarding, and what is its principle?
1. What is a block? What is a Block call?
- Block is an object that encapsulates a function and its context . Block calls are both function calls.
2. Block memory structure
Block is an Objective-C object under the hood, and its memory structure contains the following main parts:
- Block object header :
isa
Pointer: A pointer to the Block class, indicating that this is an object.flags
: Used to represent some attributes of Block, such as whether it has been copied to the heap, whether there are captured external variables, etc.reserved
: Reserved field, currently unused.invoke
: Function pointer, pointing to the execution code of the Block, that is, the implementation of the Block body.
- Block description information (
descriptor
):size
: The size of the Block structure.copy_helper
anddispose_helper
: When the Block is copied from the stack to the heap, these two function pointers are used to manage the memory of the captured external variables (if any).signature
: Block signature information, used to describe Block parameters and return value types (optional).
- Captured external variables :
- Block captures local variables in the scope in which it is defined. Copies or references to these variables are stored immediately after the Block object header and description information.
- Memory structure example
Suppose there is the following Block definition:
int a = 10;
void (^myBlock)(void) = ^{
NSLog(@"Value of a: %d", a);
};
Its memory structure is roughly as follows:
+----------------------+
| isa 指针 |
+----------------------+
| flags |
+----------------------+
| reserved |
+----------------------+
| invoke |
+----------------------+
| descriptor |
| - size |
| - copy_helper |
| - dispose_helper|
| - signature |
+----------------------+
| a |
+----------------------+
3. Block memory management
1. Three types of Blocks
There are three types of Blocks in memory, and their memory management methods are different:
- _NSConcreteGlobalBlock : Global Block, stored in the global data area, no manual memory management is required.
- _NSConcreteStackBlock : Stack Block, stored on the stack, will be automatically destroyed when leaving the scope in which it is defined.
- _NSConcreteMallocBlock : Heap Block, stored on the heap, requires manual memory management (in non-ARC environment).
When a Block is copied, different types of Blocks will have different behaviors and changes:
- Global Block (_NSConcreteGlobalBlock)
- Global Block is stored in the global data area and does not capture any external variables.
- When the global Block is copied, no real memory copy operation actually occurs, but the pointer to the Block itself is simply returned. Therefore, the copy of the global Block will not cause any memory or state changes.
- Stack Block (_NSConcreteStackBlock)
- Stack Block is stored on the stack and may capture external variables.
- When the stack Block is copied to the heap (for example, through the Block_copy function or assigned to a strong reference under ARC), the following changes occur:
- Allocate heap memory for the Block and copy the contents of the stack Block (including captured external variables) to the new location on the heap.
- If Block captures
__block
variables, these variables will also be copied to the heap together, and their__forwarding
pointers will be updated to ensure that subsequent accesses and modifications to these variables point to the copies on the heap. - The copied Block becomes a heap Block (_NSConcreteMallocBlock), and its life cycle is managed by reference counting.
- Heap Block (_NSConcreteMallocBlock)
- Heap Block is stored on the heap, and its life cycle is managed by reference counting.
- When a heap block is copied, in an ARC environment, the reference count is incremented, but no actual memory copy operation occurs. In a non-ARC environment, you need to manually manage Block reference counting and memory release.
Summarize:
- When a Block is copied, the global Block will not change. The Stack Block will be copied to the heap and become a Heap Block, and the reference count of the Heap Block will increase.
4. block capture variables
In Objective-C, a Block can capture variables external to the scope in which it is defined. This feature enables the Block to access and use variables defined outside of it. The following are some details of Block capturing external variables:
Capture method
- Basic data type variables : For local variables of basic data types (such as int, float, etc.), Block captures a copy of their value. This means that modifications to these variables within the Block will not affect the values of the original variables.
int value = 10; void (^myBlock)(void) = ^{ NSLog(@"Value inside block: %d", value); }; value = 20; myBlock(); // "Value inside block: 10"
In this example,value
the value inside the Block is still 10, even thoughvalue
it is modified to 20 outside the Block. - Object type variables : For local variables of object type, Block captures a strong reference to the object. This means that the properties of the object can be accessed and modified inside the Block, and these modifications will be reflected on the original object.
NSMutableArray *array = [NSMutableArray arrayWithObjects:@"a", @"b", nil]; void (^myBlock)(void) = ^{ [array addObject:@"c"]; }; myBlock(); NSLog(@"Array: %@", array); // "Array: (a, b, c)"
In this example,array
the Block is modified inside and a new element “c” is added.
Summarize
Blocks’ ability to capture external variables makes them very flexible and powerful, especially in asynchronous programming and callbacks. A proper understanding of how Blocks capture and use external variables is important to writing correct and efficient code.
5. How block modifies external variable values: __block
__block
Example of
If you need to modify the value of a local variable of a basic data type inside the Block, you can use __block
modifiers. This way, the Block captures the variable by reference rather than by value, allowing the variable to be modified within the Block.
__block int value = 10;
void (^myBlock)(void) = ^{
value = 20; // __block
};
myBlock();
NSLog(@"Value: %d", value); // 输出 "Value: 20"
In this example, using __block
the modifier allows the Block to modify value
the value of .
__block
What is it?
In Objective-C, __block
it is a storage type modifier used to modify variables used in Block. When a variable is __block
modified, it allows modification of the variable within the Block.
principle
- Encapsulated into a structure :
__block
Variables modified with will be encapsulated into a structure by the compiler. This structure contains the value of the variable and a__forwarding
pointer to support the process of copying the variable from the stack to the heap. - Reference capture : Unlike ordinary local variables captured by value,
__block
variables are captured by reference. This means that the Block internally accesses__block
the variable’s address, not its copy. - Stack-to-heap copying : When a Block is copied to the heap (for example, assigned to a strong reference variable or returned as a function value), all variables captured by the Block
__block
are also copied to the heap. During the copying process,__forwarding
the pointer is updated to point to the copy of the variable on the heap.
Why is it needed __block
?
- Modify external variables : Without
__block
the modifier, Block can only capture the values of external variables but cannot modify these variables.__block
Allows modifying the value of external variables inside the Block. - Support the life cycle of variables : When the Block is copied to the heap,
__block
the variables will also be copied to the heap to ensure that the variables are still valid during the life cycle of the Block. - Simplified memory management : In an automatic reference counting (ARC) environment,
__block
memory management of variables is automatically handled, including memory management when variables are copied to the heap. - Adapt to asynchronous programming mode : In asynchronous programming, it is often necessary to modify external variables in Block to store the results of asynchronous operations.
__block
Makes this model easier to implement.
In general, __block
modifiers are used to enhance the functionality of Block so that it can modify captured external variables. This is useful in asynchronous programming, callback handling, and other scenarios where external state needs to be modified in a Block. Understanding __block
the principles and functions of helps to use Block and manage memory more effectively.
6.__forwarding
__forwarding
__block
Is a mechanism related to variables in Objective-C . It is __block
a pointer in the variable structure and is used to ensure that access and modification of the variable can be performed correctly regardless of whether the variable is on the stack or the heap.
principle
__block
Encapsulation of variables :__block
Variables declared using the modifier will be encapsulated by the compiler into a structure that contains the value of the variable and a__forwarding
pointer.- The pointer points to itself : Initially, the pointer
__block
of the variable__forwarding
points to the variable itself (that is, to the structure itself). - Copied to the heap : When the Block is copied to the heap, all variables captured by the Block
__block
will also be copied to the heap. At this point,__forwarding
the pointer will be updated to point to the copy of the variable on the heap. - Uniform access method : Regardless of whether
__block
the variable is on the stack or the heap, access and modification to it__forwarding
are performed through pointers. This ensures that variable accesses and modifications always point to the correct storage location.
why needed__forwarding
- Maintain access consistency :
__forwarding
The mechanism ensures that the access and modification of variables in the Block__block
are always consistent, regardless of whether the variables are on the stack or the heap. - Supports stack-to-heap migration : When Blocks and
__block
variables are copied from the stack to the heap,__forwarding
pointers make the variable migration process smoother. It keeps the reference to the variable unchanged even if the variable’s storage location changes. - Simplified memory management :
__forwarding
The mechanism simplifies__block
memory management when variables are migrated between stack and heap. Developers do not need to care about the specific storage location of variables, they only need__forwarding
to access and modify them through pointers.
In general, __forwarding
it is __block
an important part of the variable mechanism, which ensures __block
access consistency and simplified memory management when using variables in Block. Understanding __forwarding
the principles and functions of helps to have a deeper understanding of __block
the working mechanism of Block and variables.
Summarize
__block
The principle of modifiers involves __block
the storage method, capture mechanism and internal structure of variables. By encapsulating variables as structures and capturing them by reference, __block
the value of external variables is allowed to be modified in the Block. When the Block is copied to the heap, __forwarding
the pointer ensures that the access and modification of variables are carried out through the same address, ensuring the consistency and correctness of the data.