The word “block” refers to both the block syntax in source code and the “values” generated by the block syntax.

1. The nature of the block

First, you need to know that a block is an object (why a block is an object is explained below). Block is essentially the implementation of closures on iOS.

  • So what is a closure?

A closure is a function that can read from inside another function. It can also be understood as a function defined inside a function. In essence, a closure is a bridge between the inside and outside of a function.

We all know that the scope of a variable has global variables and local variables. We can access global variables and local variables defined in a function, but we cannot access local variables outside the function.

Is there a way to access local variables inside a function from outside the function? This is where “closures” come in. Write some code to feel it.

- (void(^)(void))fun1{ int a = 100; void(^fun2)(void) = ^{ NSLog(@"a = %d",a); }; return fun2; } // call fun1 [self fun1];Copy the code

This allows access to the variable a inside fun1 outside of the function fun1.

2. Block source analysis

Let’s write a simple block to see what the source code looks like after Clang.

#include "stdio.h"
int main()
{
   void(^blockName)(void) = ^{
   printf("abcd\n");
   };
   blockName();
   return 0;
}
Copy the code

Clang-rewrite-objc a.c after block source code

Struct __block_impl {// struct __block_impl {// block is an object. void *isa; // all struct Pointers starting with *isa can be considered objects in objc, int Flags; int Reserved; void *FuncPtr; // function pointer, block to execute the code segment}; Struct __main_block_desc_0 {size_t reserved; struct __main_block_desc_0 {size_t reserved; Size_t Block_size; } // the __main_block_desc_0 structure instance is initialized, __main_block_desc_0_DATA = {0, sizeof(struct __main_block_IMPL_0)}; Struct __main_block_impl_0 {// (1) struct __block_impl; Struct __main_block_desc_0* Desc; struct __main_block_desc_0* Desc; // (3) block struct __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, Int flags=0) {// Block isa points to the _NSConcreteStackBlock pointer, which means that when a block is declared, it is an object of the _NSConcreteStackBlock class. impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; // impl.FuncPtr = fp; // function pointer Desc = Desc; }}; Static void __main_block_func_0(struct __main_block_impl_0 *__cself) {printf("abcd\n"); struct __main_block_impl_0 *__cself) {printf("abcd\n"); } int main() {// Block syntax constructor call void(*blockName)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA)); / / block call ((void (__block_impl *) (*)) ((__block_impl *) blockName) - > FuncPtr) ((__block_impl *) blockName); return 0; }Copy the code

2.1 First look at block syntax in the source code

// Block syntax ^{printf("abcd\n"); };Copy the code

Clang after the source

static void __main_block_func_0(struct __main_block_impl_0 *__cself) {

   printf("abcd\n");
   }
Copy the code

Through the source code after Clang, We can see that the block syntax is converted to a C function __main_block_func_0 (the converted C function name is the function name of the block syntax (main) + block_func + The argument __cself is a struct pointer to the block value. It is of type __main_block_IMPL_0

2.2 The __main_block_IMPL_0 constructor & call

(1) The __main_block_IMPL_0 constructor call

   void(*blockName)(void)  =
 ((void (*)())&__main_block_impl_0(
(void *)__main_block_func_0, &__main_block_desc_0_DATA));
Copy the code

Simplify the above code

Struct __main_block_IMPL_0 temp = __main_block_IMPL_0; struct __main_block_impl_0 temp = __main_block_impl_0 (__mian_block_func_0,&__main_block_desc_0_DATA); Struct __main_block_impl_0 * blockName = &temp; struct __main_block_impl_0 * blockName = &temp;Copy the code

The above part of the corresponding source is

void(^blockName)(void) = ^{
   printf("abcd\n");
   };
Copy the code

Assigning a Block generated by Block syntax to Block type variable blockName is equivalent to assigning a pointer instantiated from the __main_block_IMPL_0 structure to the variable blockName.

A block is an instance of a __main_block_IMPL_0 structure generated on the stack

Let’s take a look at how an instance of the __main_block_IMPL_0 structure is constructed.

__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) { impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; // impl.FuncPtr = fp; // function pointer Desc = Desc; }Copy the code
  • The first argument: function pointer *fp, which corresponds to __main_block_func_0
  • The second argument: __main_block_desc_0 struct instance pointer, which corresponds to __main_block_desc_0_DATA

2.3 Invocation of block

   blockName();
Copy the code

Clang after the source

   ((void (*)(__block_impl *))
((__block_impl *)blockName)->FuncPtr)((__block_impl *)blockName);
Copy the code

Again, let’s simplify the source code

(*blockName->impl.FuncPtr)(blockName)
Copy the code

The simplified code simply calls a function using a function pointer, passing a block as an argument to the function. It is also stated here that the __cself argument to the __main_block_func_0 function points to a block value.

Conclusion: This is my summary of blocks in the book Objective-C Advanced Programming iOS and OS X Multithreading and Memory Management. Where there are deficiencies, welcome Pointers.