Block data structure

struct __ArcClass__TestArc_block_impl_0 {
  struct __block_impl impl;
  struct __ArcClass__TestArc_block_desc_0* Desc;
  int age;
  __ArcClass__TestArc_block_impl_0(void *fp, struct __ArcClass__TestArc_block_desc_0 *desc, int _age, int flags=0) : age(_age) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp; Desc = desc; }};Copy the code
  • struct __block_impl impl
struct __block_impl {
      void *isa;
      int Flags;
      int Reserved;
      void *FuncPtr;
};       
Copy the code

When a block is defined, an underlying structure representing the block, __ArcClass__TestArc_block_impl_0, is generated. This structure has an IMPL member variable of type __block_IMPL and a member variable representing the capture variable. The impl isa represents the block type, and FuncPtr represents the actual call method of the block, which takes the parameter __ArcClass__TestArc_block_impl_0.

Intercept variable

  • A static variable whose value can be changed within a block because the underlying block captures the address
  • Global variables can be changed directly in blocks. Blocks do not capture global variables, but use them directly, so they can be changed directly
  • The auto variable requires the __block modifier to modify

Block memory management

The type of the Block

There are three types of blocks, which you can see by calling the class method or isa pointer, They all inherit from the NSBlock type NSGlobalBlock the global block does not access the auto variable NSStackBlock stack the block accesses the auto variable NSMallocBlock heap block __NSStackBlock__ calls copy

Block copy

In an ARC environment, the compiler automatically copies blocks on the stack to the heap as needed, such as the following

  • Block as a function return value
  • Assigns a block to a __strong pointer
  • Block is used as a Cocoa API method name containing a method parameter called usingBlock
  • Block as a method parameter of the GCD API

Memory management of Block variables

  • The auto variable of the base data type, when blocks on the stack are copied to the heap, is directlyCopy the captured basic data type variables to the heap
  • The auto variable of the object type. When the variable is modified by a strong reference, copy is called when the block is copied to the heap. The _Block_object_assign function inside copy is called.A strong reference is made to the captured object variable
  • The auto variable of the object type. When the __weak variable is modified, the block copied from the stack to the heap will still call copy. The _Block_object_assign function inside copy will be called, butStrong references to variables decorated with __weak will no longer be made
  • The __block modified auto variable is wrapped underneath as a __Block_byref_age_0 object, When a block is copied from the stack to the heap, the copy function in __main_block_desc_0 is called on the __Block_byref_age_0 objectStrong referenceDispose function is called when removing to remove strong references.

A circular reference to a Block

  • __weak: When the person is freed, the __weak person in the block points to nil
  • __unsafe_unretained: When person is freed, the __unsafe_unretained person in the block does not point to nil, resulting in a wild pointer
  • __block: Manually sets nil

__block qualifier

Can be used to solve a problem where the value of the auto variable cannot be modified inside a block, and the compiler wraps the block variable as an object. __block cannot modify global or static variables.

__block structure

For __block variables, the underlying layer encapsulates an object that accesses the real variable by pointing __forwarding to itself.

__forwarding pointer

  • When a block is on the stack, it gets the __forwarding pointerThe __block structure in the stack
  • When a block is on the heap, it gets the __forwarding pointerA __block structure in the heap

Why access through __forwarding?

This is because if the __block variable is on the stack, it can be accessed directly, but if it has been copied to the heap, it can be accessed on the stack. Therefore, __forwarding should find the address on the heap first, and then value it

__block memory management

  • When a Block is on the stack, there is no strong reference to a __block variable.

  • When a Block is copied to the heap, the Block’s internal copy function is called, which internally calls the _Block_object_assign function. The _Block_object_assign function retains a strong reference to the __block variable.

  • When a Block is removed from the heap, its internal dispose function is called, which calls the _Block_object_dispose function \, The _Block_object_dispose function automatically releases the referenced __block variable (release)