The classification of the block

  • Create a block.c file
#include "stdio.h"

int main(a){

    int a = 18;
    void(^block)(void) = ^ {printf("LG_Cooci - %d",a);
    };
    
     block(a);return 0;
}

Copy the code
  • Open the terminal to the current file path
  • Input orderXcrun-sdk iphonesimulator clang-s-rewrite-objc-fobjc-arc-fobjc-Runtime =ios-14.4 block.c
  • Generates a.cpp file with the same name

  • This is the code for the corresponding block

  • So this is the structure of the block

  • Here we find an int a, which is generated if the block captures an external variable, or if no external member variable is captured.

  • __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _a, int flags=0) : A (_a) is a little bit weird because we’ve actually done the assignment to a = _a.

  • Isa = isa stack block, because it’s still compilation, it’s not really running, so the stack block here isa heap block that needs to be looked at

  • Function storage and call

  • 1. At the beginning there was a function method__main_block_func_0
  • 2. Methods are called when a block is created__main_block_impl_0Pass in the previous function method as the first argument, called pt, and saveimpl.FuncPtr = fp;.Call block) - > FuncPtrThis is where the block starts calling the function method that we just put in there.
  • 3. Block calls__main_block_func_0Passing in a parameter__cselfSo this is the block,int a = __cself->a; // bound by copyHere we take the value of a in the block and assign it to a temporary variable and print it.

Function analysis of __block

  • Add a __block

  • Recompile view

The type of discovery has changed. Int A becomes__Block_byref_a_0 *a

  • So we’re going to take the memory address of A, and we’re going to initialize the structure. The first value of the structure is 0, the second value is the memory address of A, and the third value is the memory size of 18 lengths.

  • *__forwardingStore the memory address of A.

  • Block is created when the body of the mechanism__Block_byref_a_0 aIs passed in for saving

  • A = a forwarding

  • When a block is called, the value a is the address, and when the address is assigned, the address of the temporary variable is the same as before, and the pointer is assigned.

Conclusion: __block generates a __Block_byref_a_0 structure that lets the block capture the address values of the member variables, rather than simply the values, and place the address values of the variables that the block does not recognize. The function of modifying a memory address is complete.

Test and Debug process

  • Write a simple block

  • Open assembly debugging

  • Notice that objc_retainBlock is entered here

  • Block_copy is entered

See libclosure-79 for the underlying source code

  • 1. The underlying structure of a block is this structure
    • 1. Isa indicates the type of block to which isa is directed
    • 2. Flags is a flag
    • 3. Reserver is process data
    • 4. Invoke stores the calling function
    • 5. Descriptor Other related descriptions
  • If it’s freed, if it’s a global block, it returns otherwise it goes to the next step.

  • _Block_copyBlock creation is compiled as a stack block and becomes a heap block only after block_copy is executed. When the runtime discovers that an external variable has been captured, it captures as much memory as it needs to

Apply for a memory space, copy the contents of the stack block, become a heap block

Here we re-mark the bitheap block

  • Block_descriptor_1 *descriptor;

This is an optional argument for contiguous memory, and the data structure varies depending on the block type.

  • If the type is Block_descriptor_2 there are copy and dispose methods, Function

How do I make Block_descriptor_2

  • Find that the Block_descriptor_2 is obtained by panning the Block_descriptor_1 size

  • Same thing for Block_descriptor_3,

  • Case picture Introduction

CPP analyzes the entire process

  • Write a simple block in the viewController.

  • After the terminal is turned into a CPP file, the execution of the block is analyzed

  • Create a block

  • A block that generates such a structure

  • Look at desc and see that the memory space was assigned to it when the block was created

  • Copy function and dispose function

Copy actually calls the _Block_object_assign function,

  • The correlation processing of captured variables, that is, different types of member variables are captured, which is done differently here

  • BLOCK_FIELD_IS_OBJECT: common object typeBLOCK_FIELD_IS_OBJECTAddress pointer assignment after arc system function processing.
  • BLOCK_FIELD_IS_BLOCK: Block type. Block_copy operation is performed to save the address pointer assignment of this block object.

Here is the __weak, __block modifier, _Block_byref_copy

  • If it is not a normal object, the reference count +1,

copy->forwarding = copy; src->forwarding = copy;The variable forwarding is the same as the variable forwarding in my block, so the two are the same thing.

  • The __Block_byref_objc1_0 object modified by __block is last converted to this type

  • Looking at the CPP file, the structure looks like this

  • Isa = 8 bytes
  • forwarding 8
  • flags 4
  • size 4
  • Two functions 8 + 8
  • objc1

Once the structure is created, byref_keep = is the __Block_byref_id_object_copy_131 function

Block_objc_assign is called again

That’s where it’s called, +40 bytes translation is just fine__Block_byref_objc1_0Objc1 in the structure

Recursively one call here. Therefore, it is concluded that block captures variables differently depending on their type. The release of a block, byref_destroy, is done differently depending on the type.