directory

1. Block type

2. Copy of block

3. Copy analysis of the auto variable of block object type

4. Function and principle of __block


The type of the block

  • There are three types of blocks, which you can see by calling the class method or isa pointer. They are all derived from the NSBlock type
  1. NSGlobalBlock (_NSConcreteGlobalBlock) Global block
  2. NSStackBlock (_NSConcreteStackBlock) Stack block
  3. NSMallocBlock (_NSConcreteMallocBlock) Heap block

The memory distribution of the three blocks is as follows:

The differences and connections between different types of blocks:

  • Each type of block calls copy as shown below

Block of copy

In the actual development scenario, we often use block to access the auto variable, so in the MRC environment we need to use the copy keyword, to convert stack blocks to heap blocks, avoid stack blocks out of scope is released;

Suggested writing:

@property (copy, nonatomic) void (^block)(void);
Copy the code

In ARC, the compiler automatically copies blocks on the stack to the heap as required. Copy is the same as strong.

@property (strong, nonatomic) void (^block)(void);
@property (copy, nonatomic) void (^block)(void);
Copy the code

In an ARC environment, there are several cases where the compiler automatically copies blocks on the stack to the heap as appropriate:

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

Copy analysis of the auto variable of the block object type

  • Let’s look at the stack block copy of the auto variable of the object type:

Write a Person class, add the dealloc method, and print “Person-dealloc” when the Person is released

To enable the MRC environment:

Look at the following code:

  • It defines a block that refers to a peron auto variable, and we said earlier that any block that refers to an auto variable, without copy, is a stack block.

MRC environments do not automatically copy, so the TestBlock below is a stack block

The block does not have a strong reference to person (person is of type __strong by default).

  • When we copy the block, we find that the person is not freed, indicating that the block strongly references the person

Let’s set the ARC mode again: change person to weak reference

Finding the Person freed indicates that the block has a weak reference to the person

To verify this, let’s switch to C++ and look at the internal implementation:

You can see that the person pointer modifier inside bolck is __weak when person is __weak

The person modifier inside bolck is __strong when person is the default (__strong) modifier

  • When a block is copied to the heap:
  1. The copy function inside the block is called
  2. Copy calls the _Block_object_assign function internally
  3. The _Block_object_assign function performs operations based on the __strong, __weak, and __unsafe_unretained modifier of the auto variable, generating a retained or weak reference

  • Block removed from heap:
  1. Dispose function inside the block is called
  2. The _Block_object_dispose function is called internally
  3. The _Block_object_dispose function automatically releases the referenced auto variable (release)

Conclusion:

  • Stack blocks do not make strong references to the auto variable
  • When a stack block is copied to the heap, the reference relationship between the block and the auto variable is determined based on the modifier of the variable. __weak is a weak reference, and __strong is a strong reference.

Function and principle of __block

  • When we use a block, we sometimes need to change the auto variable inside the block, but with the familiar structure of the block, the auto variable is generated inside the block, and it can’t be assigned to the external variable directly, so we need to put __block in front of the variable, You can modify it.

So what does __block do? Let’s look at the following code:

Conversion to C++ is as follows:

__Block_byref_age_0, which contains the main information of a forwarding pointer to itself and the value of the variable, as shown below:

To sum up:

  1. __block can be used to solve the problem of not being able to modify the value of the auto variable inside a block
  2. __block cannot modify global or static variables.
  3. The compiler wraps a __block variable as an object with a corresponding structure containing the value of the variable and a forwarding pointer to itself
  • The forwarding pointer does:

The main purpose is to ensure that the stack block and the variables in the heap block are synchronized when they are copied to the heap. 1. When a block on the stack is copied to the heap, the stack block’s Forwoarding pointer points to heap Block 2. As can be seen from the code above (screenshot below), __block variables are accessed via forwoarding, so whether it is a stack block or a heap block, the final variable retrieved is a heap block variable.