(1) block definition

An anonymous function with automatic variables (local variables) is called a block

(2) block classification

There are three main types of blocks

  • __NSGlobalBlock__: globalblock, stored in the global area

In this case, the block has no parameters and no return value, and belongs to the global block

  • __NSMallocBlock__: heap areablockBecause theBlocks are both functions and objects

The block accesses an external variable, the underlying copy of A, so it’s a heap block

  • __NSStackBlock__: the stack zoneblock

Where the local variable A is a stack block before processing (before no copy), and a heap block after processing (after copy). Currently, there are fewer and fewer stack blocks

In this case, you can pass__weakNo strong holding,blockIt stillThe stack area block

Conclusion:

  • blockStored directly in the global area
  • ifblockAccess external variables and performblockCorresponding copy, that iscopyoperation
    • If at this pointBlocks are strong references,blockStored in theThe heap area, i.e.,Heap area block
    • If at this pointblockthrough__weakBecomes a weak reference, thenblockStored in theThe stack area, i.e.,The stack area block

Block loop reference

① Analysis of circular reference

  • Normal release: refers to theA hold BWhenAcalldeallocMethods toBsendreleaseSignal,BreceivedreleaseThe signal, if at this pointBtheretainCount(that is, reference count) is0Is calledBthedeallocmethods

  • A circular reference:A and BThey hold each other, which leads toACan’t calldeallocApproach toBsendreleaseSignal, butBI can’t receive itreleaseSignal. SoA and BThey can’t be released at this point

② Solve circular references

Do the following two pieces of code have circular references?

  • Code one kind of hairA circular reference is generatedBecause, inblockInternally usedExternal variable name, resulting inBlock is holding selfAnd theSelf originally owned blockSo it leads toSelf and block hold each other.
  • Code 2.Acyclic reference, although external variables are used, butselfThey don’t holdanimationtheblockOnly, onlyanimationholdself, does not constitute mutual possession.

There are several common ways to resolve circular references:

  • Methods (1) :weak-strong-dance— Dance between strong and weak
  • (2) :__blockModify objects (note that inblockInternal needsemptyObject, andblockMust call)
  • Method 3: Pass objectsselfAs ablockIs provided toblockInternal use
  • Mode 4: UseNSProxy

1 Mode ①: weak-strong-dance

  • ifblockThere is no nesting insideblock, direct use__weakmodifiedselfCan be

At this timeweakSelfandselfPoint to the same pieceMemory spaceAnd the use of__weakDoes not lead toselfThe reference count changes can be printedweakSelfandselfPointer address, as well asselfTo verify, as shown below

  • ifblockNested insideblockNeed to be used at the same time__weak__strong

StrongSelf is a temporary variable in the scope of the block, which releases strongSelf when the internal block is finished executing

This is breaking self’s strong reference to a block, depending on the mediator pattern, and is auto-set to nil, auto-release

②.2 Mode ②: __block modifies variables

This approach, which also relies on the mediator pattern, is manual release and modifies objects with __block, mainly because __block modifies objects that can be changed

Notice that the block here has to be called, if it’s not called, vc is not null, it’s still a circular reference, self and block are not released.

②.3 Method ③: The object self is used as a parameter

The object self is supplied as an argument to the block for internal use, with no reference counting problems

4 Mode 4: NSProxy virtual class

  • OC is a single-inheritance language, but it is based on the run-time mechanism, so NSProxy can be used to implement pseudo-multiple inheritance, filling the gap of multiple inheritance

  • NSProxy and NSObject are sibling classes, or virtual classes, that implement the protocol of NSObject

  • NSProxy is an abstract class that encapsulates message redirection. It is like a proxy, middleware, that can inherit it and rewrite the following two methods to implement message forwarding to another instance

    - (void)forwardInvocation:(NSInvocation *)invocation;
    - (nullable NSMethodSignature *)methodSignatureForSelector:(SEL)sel
    Copy the code
  • 1. NSProxy is an abstract base class that is the root class, similar to NSObject

  • 2. Both NSProxy and NSObject implement the

    protocol

  • 3. Provides a universal interface for message forwarding

** Usage scenarios **

There are two scenarios for using NSProxy

  • implementationMultiple inheritancefunction
  • To solve theNSTimer&CADisplayLinkCreated forselfStrong reference problem, referenceYYKittheYYWeakProxy

The principle of circular reference solution is to replace self with a custom NSProxy class object and use methods to implement message forwarding

The following is an implementation of the NSProxy subclass and the scenario in which it is used

  • Define a NSProxy subclass CJLProxy! [](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/797421aa58a84ee7b470ed03fd436a68~tplv-k3u1fbpfcp-watermark.image)

  • The customTCJCatClasses andTCJDogclass

  • throughTCJProxyRealize multiple inheritance function

  • throughTCJProxyResolve timerselfThe strong reference problem of

(2). 5

There are basically two ways to solve a circular reference, for example self -> block -> self

  • breakselfrightblockA strong reference to theblockProperty modifier is usedweakBut this will lead toblockIt is also released as soon as it is created, so breaking strong references from here won’t work
  • breakblockrightselfStrong reference, mainly isselfThe scope and ofblockScope communication, communication hasProxy, pass value, notification, pass parameterAnd other ways to solve the cycle, the common solutions are as follows:
    • weak-strong-dance
    • __block(blockThe inner object is empty and calledblock)
    • The objectselfAs ablockThe parameters of the
    • throughNSProxySubclass ofself

Iii. Underlying principle of Block

Mainly through clang, breakpoint debugging and other ways to analyze the Block bottom

(3). 1 block essence

  • defineblock.cfile

  • throughxcrun -sdk iphonesimulator clang -arch x86_64 -rewrite-objc block.cThat will beblock.cCompiled intoblock.cpp, includingblockAt the bottom it is compiled into the following form

By simplification we know that the equivalent block is __main_block_IMPL_0, which is a function

  • To view__main_block_impl_0, it isA structureAt the same time, it can be explainedblockIs a__main_block_impl_0Type of object, that’s why, rightblockTo be able to% @Reasons for printing.

Summary: The essence of a block is an object, a function, or a structure. Since a block function has no name, it is also called an anonymous function or code block

blockthroughclangThe relationship between the compiled source code is shown below__blockFor example, modify a variable

③ 1.1 Why does block need to be called

The underlying block has a __main_block_IMPL_0 structure of type, created by its constructor of the same name, and the first passed block’s internal implementation code block, __main_block_func_0, is expressed as FP, which is then assigned to the FuncPtr property of the IMPL, The call is then made in main, which is why the block needs to be called. If not called, the code block implemented inside the block will not execute, which can be summarized as follows

  • Function declaration: that is,blockThe internal implementation declares a function__main_block_func_0
  • Perform specific function implementations: by callingblocktheFuncPtrPointer, callblockperform

③ 1.2 How does block obtain external variables

  • Define a variable and set it toblockIn the call
  • The underlying compilation looks like this

The ain __main_block_func_0 is a copy of the value, and if you do a++ inside a block implementation, it is problematic and will cause confusion in the compiler code that a is read-only.

Summary: When a block captures an external variable, it automatically generates the same internal property to hold

③ 1.3 the principle of __block

  • rightaAdd a__blockAnd then inblockIn theafor++operation

The underlying compilation is as follows

  • mainIn theaIs encapsulated by external variablesobject
  • __main_block_impl_0,Object aThe address of the&aTo the constructor
  • in__main_block_func_0Within theaThe process isPointer to the copy, the object created at this timeaWith the object passed inaPoint to theSame memory space

Conclusion:

  • External variablesthrough__blockgenerate__Block_byref_a_0The structure of the body
  • The structure of the bodyUsed toSaves the pointer and value of the original variable
  • To generate a variableThe pointer address of a structure objectPassed to theblockAnd then inblockYou can manipulate external variables internally

The __block and non-__block modifier local variables above produce two different copies

  • The __block modification:Copy the valueDeep copy, just copy the value, and the copied value cannot be changed, pointing to a different memory space, in the case of ordinary variablesaisCopy the value
  • __block modification:Pointer to the copyShallow copy.Generated objectPoint to theSame memory space, through the case__blockModified variableaisPointer to the copy

]