Block portal 🦋🦋🦋

Exploring the nature of blocks (1) — Basic knowledge

Explore the essence of blocks (3) — basic type of variable capture

Explore the nature of blocks (4) — the type of Block

Explore the nature of blocks (5) — variable capture of object types

Exploring the nature of blocks (6) — An in-depth analysis of __blocks

In the last article, we looked at some of the basics of blocks. Now, let’s dig into the underlying structure of the Block. Start by creating a new command line project

Define a very simple block

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        The definition of / / Block
        void (^block)(void) = ^ () {NSLog(@"I am a block!");
        };
        
        / / Block calls
        block();
        
    }
    return 0;
}
Copy the code

And then, throughxcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main.cppCommand to get the compiled c++ file and add it to the project. Look directly at the end of the fileIn the main function, there is a lot of cast code, for the sake of understanding, remove the cast code (without affecting the original logic), its main function is simplified as follows

/ / 【 1.2 】
struct __main_block_impl_0 {
    
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
    
    //C++ syntax, the following function is a class constructor, the same as the name of the class, similar to oc init method, returns a structure object
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) { impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc; }};// [1.1] This function is the code block execution logic encapsulated inside the block
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {

            NSLog((NSString *)&__NSConstantStringImpl__var_folders_7__p19yp82j0xd2m_1k8fpr77z40000gn_T_main_65b8ed_mi_0);
        }

/ / 【 1.3 】
static struct __main_block_desc_0 {
  size_t reserved;// Save the variable
  size_t Block_size;/ / the size of the block
}__main_block_desc_0_DATA = { 0.sizeof(struct __main_block_impl_0)};

/ / the main function
int main(int argc, const char * argv[]) {
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 

        // [1] -------------- [1.4]
        void (*block)(void) = &__main_block_impl_0(
                                                   __main_block_func_0,
                                                   &__main_block_desc_0_DATA));

        / / [2]
        block->FuncPtr(block);
    }
    return 0;
}
Copy the code

Now let’s analyze the logic of the execution at the bottom of the system. First, follow the first line of the main function in the OC code

The definition of / / Block
        void (^block)(void) = ^ () {NSLog(@"I am a block!");
        };
Copy the code

The system does step [1.1], which encapsulates the Block into the function static void __main_block_func_0(struct __main_block_IMPL_0 *__cself){}.

In the next step [1.2], the system defines struct __main_block_impl_0 as the underlying data structure of the Block. Since it is a structure under the C++ syntax, functions can be defined in this structure. The function in this code is the __main_block_impl_0() constructor for this structure.

In the next step [1.3], the system defines the static struct __main_block_desc_0 and generates an instance __main_block_desc_0_DATA, which is used to store the related description information of the Block.

Finally, in step [1.4], the system assigns the address of the object generated by the __main_block_IMPL_0 () constructor to the block pointer. Two arguments are passed, (1)__main_block_func_0

  • And then I assign it to__main_block_impl_0->impl->funcPtr

(2)&__main_block_desc_0_DATA

  • According to the structurestatic struct __main_block_desc_0 structure

Such steps【 1 】It’s over. Let me show you the whole process in the last picture

Next, according to our OC code

/ / [2]
        block->FuncPtr(block);
Copy the code

The system will complete the block call through step [2], which is to call the function pointer encapsulated inside the block. block->FuncPtr(block);

⚠ ️ small detailsblock->FuncPtr(block);Why is there no error? Because the way our code is structured, it should beblock->impl->FuncPtr(block);Just right. Let’s seestruct __main_block_impl_0The first member of thestruct __block_impl impl;,impl Is a structure, not a pointer, so you can just move its contents tostruct __main_block_impl_0To understand thesoblock->FuncPtr(block);Is equivalent toblock->impl->FuncPtr(block);You can actually get it either wayFuncPtrCall.

At this point, the simplest underlying data structure of the Block is analyzed.

Block portal 🦋🦋🦋

Exploring the nature of blocks (1) — Basic knowledge

Explore the essence of blocks (3) — basic type of variable capture

Explore the nature of blocks (4) — the type of Block

Explore the nature of blocks (5) — variable capture of object types

Exploring the nature of blocks (6) — An in-depth analysis of __blocks