“This is the 27th day of my participation in the November Gwen Challenge. See details of the event: The Last Gwen Challenge 2021”.

The use of the __block modifier

__block can be used to solve the problem of not being able to modify the value of the auto variable inside a block

__block cannot modify global or static variables.

The compiler wraps a __block variable into an object

Does the following code compile successfully, and if so, what is the output

int a = 10;
void (^block)() = ^{
    a = 20;
    NSLog(@"a = %d",a);
};
Copy the code

Result: Failed to compile miss__block source code as follows

/ / the main function
int main(int argc, const char * argv[]) {
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 
        
        int a = 10;
        void (*block)() = ((void (*) ())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, a));
    }
    return 0;
}

//block execution address
  static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
  int a = __cself->a; // bound by copy
  NSLog((NSString *)&__NSConstantStringImpl__var_folders_kh_0rp73c0s2mvfp5gjf25j5y6h0000gn_T_main_1a12fa_mi_0,a); }Copy the code

When a block is executed, its internal function is __main_block_func_0, and a is declared in the main function. The two functions are independent of each other. For both functions, A is a local variable, and a is initialized in both functions. Modify local variables in main function, so compile error! How to change?

Solution 1: Use static

static int a = 10;
void (^block)() = ^{
    a = 20;
    NSLog(@"a = %d",a);
};
Copy the code

Because the static modified auto variables, and ultimately pass in the block is not value, but the address, pay attention to perform functions of a and the main function of a, is the same address = = > is the same a, so you can change the output of 20

Static, however, becomes a static variable and is always in memory. Option 2: Use __blcok

__block auto int a = 10;
void (^block)() = ^{
    a = 20;
    NSLog(@"a = %d",a);
};
Copy the code
struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  __Block_byref_a_0 *a; // by ref= = >auto, it isint a.__block, becomes an object}Copy the code
struct __Block_byref_a_0 {
  void *__isa;
__Block_byref_a_0 *__forwarding;= = >Pointer to its own structure int __flags; int __size; int a;= = > 10Here};Copy the code

a = 20; __forwarding->a) = 20;

__forwarding is a pointer to the structure itself, which is equivalent to a itself. In fact, it is a pointer to the structure of A to get the member a inside, and then assign to it

Pointer pass, so you can modify the auto variable by referring to the auto variable indirectly through the block

The _ forwarding pointer in __block

When a block is copied from the stack to the heap, the internal variables are also expected to be stored on the heap (to keep the lifetime of the variables manageable so that they are not recycled).

By adding variable A to the stack, the pointer on the stack points to the block on the heap, and the forwarding of the block on the heap points to itself, we can ensure that the variables that are modified and acquired are the variables on the heap

Finally, __block points to variables that point to the heap

Once an object is used/accessed within a block, the corresponding object must be managed in memory

When a block is on the stack, there is no strong reference to the __block variable. When a block is on the heap, the copy function inside the block is called, The _Block_object_assign function is called internally. The _Block_object_assign function performs operations based on the strong, weak, and unsafe_unretained parameter of the auto variable. See if the internal auto variable is strongly referenced or weakly referenced

The auto and __block variables of the object type do not generate strong references to any of them when a block is on the stack. They are always weak references. When a block is copied to the heap, _Block_object_assign- 1. Weak 2. Strong

Removed: When a block is removed from the heap, its internal dispose function is called, which calls _Block_objcet_dispose, similar to release, The auto variable is automatically released (when the reference counter =0)

Tips: when using clang to convert OC to C++ code, you may encounter the following problem: cannot create __weak reference in file using manual reference

Arc-sdk iphoneOS clang-arch arm64-rewrite-objc-fobjc-arc-fobjc-Runtime =ios-8.0.0 main.m