The underlying principles of Blocks in iOS

The author of this article mainly refers to the book " Objective-C Advanced Programming: iOS and OS X Multithreading and Memory Management " written by Kazuki Sakamoto, Tomohiko Furumoto and translated by Li Hua. In my daily work, I encounter a lot of confusion related to Block, such as: Block's circular reference problem . So after reading the book repeatedly, I decided to summarize a related article about Block. If you still want to learn more about Block, the author recommends reading the above books directly. Due to the limited level of the author, there are bound to be flaws in the article, and I beg you readers to enlighten me. Block variable capture only targets variables used in Block. Unused variables will not be appended to the C language structure, which means they will not be captured by Block.
__xxx(外部函数名)_block_impl_x(序号,从0开始)

1. Capture of value variable types (such as int)

1. Global variables
  • It will not be captured because it can be directly accessed in the C language function of Block transformation and can be used directly without any changes.
2. Global static variables
  • It will not be captured because it can be directly accessed in the C language function of Block transformation and can be used directly without any changes.
3. Local static variables
  • Capture , because the variable is outside the scope of the C language function of the Block transformation, a pointer will be generated pointing to the variable and saved in the C language structure of the Block transformation.
4. Ordinary local variables
  • The capture mechanism that does not capture
    local static variables seems to be applicable to the capture of local variables, but why hasn't the official done this?

Let me talk about my understanding here, 1) Because the original intention of local variables of ordinary value types is only to be used in the local scope, they do not want to be accessed by other places beyond the scope, so there is no need to capture them. 2) The purpose of capturing is that when the operation is performed inside the Block, the external variables can also be modified in the same way. For ordinary local variables of object type, such as an Array object, after adding an Object to it, obviously the external Array will also be added, because essentially they point to the same memory area. For ordinary local variables of value type, such as int type, if we want to modify it in the Block, the only way is to modify its value, but this is not allowed. Modifiers need to be added, but after adding __blockthe __blockmodifiers , it becomes __blocka structure, no longer an ordinary value type.

2. Capture of pointer variable type (object) (such as: NSString)

Corresponding pointer variables (objects) are generated inside the Block structure , such as referencing external array objects, and id __strong arraymember variables are generated inside the Block. The memory management of this member variable __xxx_block_copy_xholds the external object by calling the function inside the Block. __xxx_block_dispose_xto release the object.

__strongTherefore, objects using local variables with modifiers ( default generated objects are of strong type ) in Block and variables copied to the heap __blockwill exist beyond the scope of their variables because they are held by Block.

Note : If the external object is __weakmodified by the modifier, the corresponding weak type object will be generated inside the Block structure. When the external object is released, because the weak pointer is automatically set to nil, the object inside the Block structure is set to nil. nil, although any method call can be made on it and it will not cause the program to crash, it will have no result. This is also often used to solve Block circular reference problems.

3. The use of __block for value variables (such as: __block int val = 0)

Generate __blocka structure. __blockA value type member variable is generated inside the structure, and its value is equal to the value of the external value variable. At this time, when modifications are made inside the Block, it will be done in the following form:

	__Block_byref_val_0 *val = __cself->val;

	(val->__forwarding->val) = 1;

Access itself through __blockthe structure __forwardingpointer (or a copy of itself on the heap) to change __blockthe value inside the structure.

__block__xxx_block_copy_xThe memory management of member variables holds the object by calling the function inside the Block and __xxx_block_dispose_xreleases the object.

4. The use of __block on pointer variables (objects) (such as: __block NSString *str)

__blockA structure will also be generated , and __blockan object type member variable will be generated inside the structure, which refers to an external object.

__block__Block_byref_id_object_copy_xThe memory management of member variables holds the object by calling the function inside the Block and __Block_byref_id_object_dispose_xreleases the object.

Note : If the external object is __weakmodifier and __blockmodified, __blockthe corresponding __weaktype of object will be generated inside the structure. When the external object is released, because the weak pointer is automatically set to nil, __blockthe object inside the structure is set to nil. Although any method call can be made on it and it will not cause the program to crash, it will have no result.

5. __forwarding pointer of __block variable

	__Block_byref_val_0 *val = __cself->val;

  	(val->__forwarding->val) = 1;

Inside the Block, you can obtain the held __blockvariables and modify the values ​​of the variables in the above way, but __forwardingdoes the existence of pointers seem redundant?

__blockThe pointer inside the variable __forwardingallows __blockthe variable to be accessed correctly regardless of whether the variable is configured on the stack or the heap __block. Here’s why:

Configuration storage domain of __block variable The impact when blocks are copied from the stack to the heap
the stack Copied from stack to heap and held by Block
heap Held by Block

Here is an analysis of a situation

	__block int val = 0;

	void (^blk)(void) = [ ^{
    
     ++val; } copy ];

	++val;

	blk();

	NSLog(@"%d",val);

Print result: 2

At first, __blockthe variables and Block are on the stack. When the Block calls copya method, the Block is copied to the heap, and the variables called internally __blockare also copied from the stack to the heap and are held by the Block. At this time, __blockthe variables have variables on the stack. And variables on the heap, variables on the stack __blockwill __forwardingreplace the value of the member variable pointer with __blockthe address of the structure instance copied to the variable on the target heap.

There was a misunderstanding here, and I learned it again. At this time, variables on the stack/heap can be accessed at the same time __block, but the same __blockvariable is ultimately accessed. If no __blockcopy of the variable from the stack to the heap occurs, then __blockthe variables accessed inside/outside the Block belong to the same variable on the stack. __blockvariable, and vice versa to access the same __blockvariable on the heap

The specific reasons are as follows:

Configuration storage domain of __block variable Access process (after copying __block variable)
the stack val (stack) -> __forwardingpointer (pointing to val on the heap) -> num
heap val (heap) -> __forwardingpointer (pointing to itself on the heap) -> num

Here is an original quote from the book: Through this function, whether you use __blockvariables in Block syntax, outside Block syntax, or __blockthe variables are configured on the stack or heap, you can access the same __blockvariable smoothly.

6. Timing of copying block from stack to heap

When ARC is enabled, in most cases the compiler will make appropriate judgments and automatically generate code to copy the Block from the stack to the heap. The following situations are applicable:

1. copyWhen calling the instance method of Block

2. When Block is used as the return value of a function or when Block is passed in the parameter of a function

3. When assigning Block to __stronga class with modifier id type or to a member variable of Block type

4. When passing a Block in usingBlocka Cocoa framework method or Grand Central DispatchAPI contained in the method name

However, sometimes it is necessary to manually copy the Block from the stack to the heap. In this case, we use the " copyinstance method".

Guess you like

Origin blog.csdn.net/weixin_44758107/article/details/127627957