• blockIntroduction to the

    A Block is an object that encapsulates a unit of work and is a piece of code that can be executed at any time. They are essentially portable anonymous functions that can be passed in as arguments to and returned from methods and functions. — (translated from official document)

    Block is an extension of the C language that was not defined as part of the ANSI C standard, but was added to the language by Apple. Blocks look more like functions that can pass arguments to them, and blocks can also have return values.

  • blocktype

    • __NSGlobalBlock__Global block, stored in a global area

      Let’s start with the following codeDiscovery is simply a declarationblock.blockNo entry, no entryblockThe internal code block is simply printed without reference to external variablesblockType is__NSGlobalBlock__

    • __NSStackBlock__The stack area block

      This is the type before the outside variable is processed__NSStackBlock__After the external variables are processed, the underlying values will beblockCopy from stack to heap. Under ARC, the compiler does a lot of optimizations, often missing the essence of the above code output is not found because the compiler pairs__NSStackBlock__The copy operation is automatically performed. Instead ofMRCYou can see that it prints whether the variable is being processed or not__NSStackBlock__

      Automatic Reference Counting in Build Settings is changed to NO.

      Of course you can use it__weakmodifiedblockNot without strong referencescopySo it’s printed at this pointblockOr the stack areablock

    • __NSMallocBlock__Heap area block

      The stack areablockThe bottom copy then becomes the heap areablock

  • blocknature

    • Code exploration after compilation

      Start by writing a simple block and look at the compiled code The bottom layer is found to be__main_block_impl_0The address of the function assigned toblockNow let’s see__main_block_impl_0The structure of the You can see it hereblockThe essence is actually a structure, and there is in the structureisaYou can also sayblockIt is essentially an OC object, an OC object that encapsulates the function call and the environment in which the function is called

      You can also see the assignment of a function in the structure, which explains why a block needs to be called before it executes a code block, because underneath it is just a pointer assignment, not an active call.We can also see that the compiled code is called when it is calledFuncPtrAnd willblockPassed as an input parameter

  • blockHow to capture variables

    I wrote a simple block with no input and no external variables, and I wrote another block that uses external variablesblockLook at the bottom layerblockDefine a variable a in the outside world, print a in the code block, and see the compiled code:

    • conclusion

      Find the underlyingblockThere is an extra parameter with the same name in the structure. When initializing, the external variable is assigned to the same variable. The local variable will generate a variable for value copy, and the global variable will use the external variable without capturing the variable

  • __blockThe principle of

    blockThe direct modification outside the code block is not used__blockReturns the following error when modifying a variableNow we’re using__blockThe modifier found that no errors were reported and the modification succeededView the compiled code through ClangDiscovery after compilationaThis is where the address is not just a simple numeric value and is converted to__Block_byref_a_0typeDiscovered by compiled code__Block_byref_a_0It’s a structure, and thenblockWe also have one more structure__Block_byref_a_0Type of pointer so low-levelaIt’s a copy of the pointer to the outside worldaThe variable refers to the same piece of memory address, so it is used in this case__blockThe modified variable can be successfully modified

  • blockTrue typeBlock_layout

    • Find the block’s true type through code debugging

      Discover the first declaration by assembly traceblockThe first thing you will do is go toobjc_retainBlockGo to the figure belowNow we go to the next sign breakpointobjc_retainBlockAnd found thatobjc_retainBlockMethod will jump to_Block_copyMethod, the break point continues down and finds the first entrylibobjc.A.dylibIn the library_Block_copyMethod, inside the method, there’s another jump_Block_copyMethod, same continue to follow the discovery intolibsystem_blocks.dylibIn the library_Block_copyMethod, at this point we find the source codeblockThe true type offoundblockThe true type ofBlock_layout

    • Block_layoutThe source code to explore

      Through the source code found that the bottom is a structure as shown in figure flagsidentification

      • 1 a –BLOCK_DEALLOCATING, release flag, – commonBLOCK_NEEDS_FREEDo bits and operations, passed in togetherFlagsTo inform theblockCan be released.
      • 16 – lowerBLOCK_REFCOUNT_MASK, stores the value of the reference count; Is an optional parameter
      • 24th –BLOCK_NEEDS_FREE, low 16 is a valid flag, according to which the program decides whether to increase or decrease the value of the reference count bit;
      • 25 –BLOCK_HAS_COPY_DISPOSE, whether a copy helper function is available;
      • 26 –BLOCK_IS_GC, whether or notblockDestructor;
      • 27th, indicating whether there is garbage collection; //OS X
      • 28 –BLOCK_IS_GLOBALIs a global block;
      • 30th –BLOCK_HAS_SIGNATURE, andBLOCK_USE_STRETIn contrast, judge the presentblockWhether you have a signature. Used forruntimeIs dynamically called.

      descriptorDescription:

      Additional information about a block, such as the number of variables to keep, the size of the block, and Pointers to auxiliary functions to copy or dispose. Have three kinds of

      • Block_descriptor_1Is choice
      • Block_descriptor_2Block_descriptor_3It’s all optional

      Take a look atBlock_descriptor_2andBlock_descriptor_3Constructor ofFound throughBlock_descriptor_1The memory address of the

  • blockThree-layer copy analysis

    Note: The only time you can start a triple copy is when an object decorated with __block is captured in a block

    • Layer 1 copy_Block_copy

      This layer of copy is mainly to beblockCopy from stack to heapSource code is relatively simple, mainly divided into the following steps

      1. First check whether the input parameter is null and return null
      2. judgeblockWhether to release, do not copy
      3. Check whether it is globalblockIf yes, do not copy
      4. Finally, the stack block, the first step is to create memory space
      5. And then there’s memory copy, which willaBlockCopy toresult
      6. The last is a simple assignment and returnresult
    • Layer 2 Copy_Block_byref_copy

      Mainly for external variables__blockI’m going to copy it when I modify itBlock_byrefThe structure is from below_Block_object_assignSource analysis knows if it is__blockThe decorated object is given_Block_byref_copyWe’ll see at this point_Block_byref_copyThe source ofFrom the source can see why to use__blockModify the variable inblockCan directly modify the corresponding value, I look at the compiled codeFound in__blockModified object converted to__Block_byref_person_0Type to see__Block_byref_person_0The structure of the bodyI found two extra functions__Block_byref_id_object_copyand__Block_byref_id_object_dispose, temporarily do not know how to use these two functions, this time we go back to the source first lookBlock_byrefThe structure of the bodyFound a common oneBlock_byrefI don’t have these two functions in my structure, butBlock_byref_2There happen to be two functionscopyanddisposeAnd then look at_Block_byref_copyFunction source found if presentcopyanddisposeMethod will be calledcopymethodsBack to the compiled codecopyThe implementation of theDiscovery is called again_Block_object_assignMethod, this is the normal object passed to the system arc to process, and then make a pointer copy, so that the copy layer is found

    • Layer 3 copy_Block_object_assign

      First look at the compiled source codeIt turns out there are two ways__main_block_copy_0and__main_block_dispose_0The implementations inside the method call, respectively_Block_object_assignand__main_block_dispose_0, can also know the source code of the two methods corresponding toBlock_descriptor_2In thecopyanddisposeNow let’s see_Block_object_assignSource code implementationThere are three main steps for discovery through source code

      1. Determine if it is a simple common object type and hand it over to ARC
      2. If the type is block, it is given_Block_copyTo deal with
      3. If the object is decorated with __block_Block_byref_copyThe source code analysis of this method can be seen
  • blockA circular reference

    • Causes of circular references

      The root cause of circular references is that they cannot be freed from each other, such as when the current class has oneblockAnd then there’s a propertynameIf theblockThe use ofnameAnd so onblockWill have only the current object (which was also analyzed above,blockThe internal structure will add an identical object to hold the current object, and the underlying object will make a pointer copy and the reference count will be incremented by one.

    • Circular reference solutions
      • **__weak and __strong combine **
        • If it’s simpleblockIs required to useselfProperty directly used in__weakThis will do, so that both Pointers point to the same memory address but use__weakThe modifier does not increment the reference count by one.
        • If it isblocknestedblockIn the case
          __weak typeof(self) weakSelf = self;
          self.tdBlock = ^(void){
              __strong typeof(weakSelf) strongSelf = weakSelf;
              dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                  NSLog(@"%@",strongSelf.name);
              });
          };
          self.tdBlock();
          Copy the code

          This situation is the same outside use__weakTo embellish, but in the first oneblockIt’s in use__strongTo modify. Should be__strongThe modified variable is a local variable in the code block, soblockThe code is automatically released after execution, so there is no circular referenceblockIn the use__strongModified? Mainly because of the insideblockIs a delayed operation if not used__strongModifier then completes the destructorweakSelfIt becomesnilSo in the nestedblockI got it inweakSelfNil, that’s what we’re using__strongIn order to prolongweakSelfDeclare the cycle so that it is nested inblockDestroy them after completion of execution

      • __block decorates a variable

        use__blockRetouching is used inblockInternally you can modify the value of a variable’s attribute, as well as in the definitionblockwhenselfThe reference count is incremented by one, but the variable can be set to 0 after the use is completenil, thenselfThe reference count is then reduced by one, so there is no circular reference. (Note: this method block must be called and if the variable is not called it will cause a circular reference)
      • Object self as the argument

        Passed in as a parameter, at this pointselfIt is pushed as a temporary variable, so it is not held, and therefore it is not referenced in a loop (function arguments are on the stack and are automatically allocated and released by the compiler)
      • NSProxy virtual class
        • OCIs a single inheritance only language, but it is based on the runtime mechanism, so it can passNSProxyTo realize pseudo-multiple inheritance and fill the blank of multiple inheritance
        • NSProxy NSObjectIt’s a sibling class, or a virtual class, but it’s implementedNSObjectThe agreement
        • NSProxyA message redirection encapsulates an abstract class, like a proxy middleware, that can inherit it and override the following two methods to forward a message to another instance

          - (void)forwardInvocation:(NSInvocation *)invocation;

          - (nullable NSMethodSignature *)methodSignatureForSelector:(SEL)sel