IOS martial arts esoteric article summary
Writing in the front
I’m sure you’re familiar with Blocks and see them in your daily development. This article will explain the concept of block, BLCOK circular reference, block bottom three aspects
A possible secret Demo for this section
First, Block preliminary study
(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 areablock
Because 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__weak
No strong holding,block
It stillThe stack area block
Conclusion:
block
Stored directly in the global area- if
block
Access external variables and performblock
Corresponding copy, that iscopy
operation- If at this point
Blocks are strong references
,block
Stored in theThe heap area
, i.e.,Heap area block
- If at this point
block
through__weak
Becomes a weak reference, thenblock
Stored in theThe stack area
, i.e.,The stack area block
- If at this point
Block loop reference
① Analysis of circular reference
-
Normal release
: refers to theA hold B
WhenA
calldealloc
Methods toB
sendrelease
Signal,B
receivedrelease
The signal, if at this pointB
theretainCount
(that is, reference count) is0
Is calledB
thedealloc
methods -
A circular reference
:A and B
They hold each other, which leads toA
Can’t calldealloc
Approach toB
sendrelease
Signal, butB
I can’t receive itrelease
Signal. SoA and B
They can’t be released at this point
② Solve circular references
Do the following two pieces of code have circular references?
- Code one kind of hair
A circular reference is generated
Because, inblock
Internally usedExternal variable name
, resulting inBlock is holding self
And theSelf originally owned block
So it leads toSelf and block hold each other
. - Code 2.
Acyclic reference
, although external variables are used, butself
They don’t holdanimation
theblock
Only, onlyanimation
holdself
, 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) :
__block
Modify objects (note that inblock
Internal needsempty
Object, andblock
Must call) - Method 3: Pass objects
self
As ablock
Is provided toblock
Internal use - Mode 4: Use
NSProxy
1 Mode ①: weak-strong-dance
- if
block
There is no nesting insideblock
, direct use__weak
modifiedself
Can be
At this timeweakSelf
andself
Point to the same pieceMemory space
And the use of__weak
Does not lead toself
The reference count changes can be printedweakSelf
andself
Pointer address, as well asself
To verify, as shown below
- if
block
Nested insideblock
Need 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 also depends onThe mediator pattern
, belong toHand release
Is through__block
Modify objects, mainly because__block
The modified object 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
It’s basically the objectself
As a parameter, provided toblock
For internal use, there will be 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
Usage scenarios
There are two scenarios for using NSProxy
- implementation
Multiple inheritance
function - To solve the
NSTimer&CADisplayLink
Created forself
Strong reference problem, referenceYYKit
theYYWeakProxy
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
-
Custom one
NSProxy
A subclass ofCJLProxy
-
The custom
TCJCat
Classes andTCJDog
class -
through
TCJProxy
Realize multiple inheritance function -
through
TCJProxy
Resolve timerself
The strong reference problem of
(2). 5
There are basically two solutions to looping applications, self -> block -> self for example
- break
self
rightblock
A strong reference to theblock
Property modifier is usedweak
But this will lead toblock
It is also released as soon as it is created, so breaking strong references from here won’t work - break
block
rightself
Strong reference, mainly isself
The scope and ofblock
Scope communication, communication hasProxy, pass value, notification, pass parameter
And other ways to solve the cycle, the common solutions are as follows:weak-strong-dance
__block
(block
The inner object is empty and calledblock
)- The object
self
As ablock
The parameters of the - through
NSProxy
Subclass ofself
Iii. Underlying principle of Block
Mainly through clang, breakpoint debugging and other ways to analyze the Block bottom
(3). 1 block essence
-
define
block.c
file -
through
xcrun -sdk iphonesimulator clang -arch x86_64 -rewrite-objc block.c
That will beblock.c
Compiled intoblock.cpp
, includingblock
At 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 structure
At the same time, it can be explainedblock
Is a__main_block_impl_0
Type of object, that’s why, rightblock
To 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
block
throughclang
The relationship between the compiled source code is shown below__block
For 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,block
The internal implementation declares a function__main_block_func_0
Perform specific function implementations
: by callingblock
theFuncPtr
Pointer, callblock
perform
③ 1.2 How does block obtain external variables
- Define a variable and set it to
block
In 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
- right
a
Add a__block
And then inblock
In thea
for++
operation
The underlying compilation is as follows
main
In thea
Is encapsulated by external variablesobject
__main_block_impl_0
,Object a
The address of the&a
To the constructor- in
__main_block_func_0
Within thea
The process isPointer to the copy
, the object created at this timea
With the object passed ina
Point to theSame memory space
Conclusion:
External variables
through__block
generate__Block_byref_a_0
The structure of the bodyThe structure of the body
Used toSaves the pointer and value of the original variable
- To generate a variable
The pointer address of a structure object
Passed to theblock
And then inblock
You can manipulate external variables internally
The __block and non-__block modifier local variables above produce two different copies
The __block modification
:Copy the value
–Deep copy
, just copy the value, and the copied value cannot be changed, pointing to a different memory space, in the case of ordinary variablesa
isCopy the value
__block modification
:Pointer to the copy
–Shallow copy
.Generated object
Point to theSame memory space
, through the case__block
Modified variablea
isPointer to the copy
③.2 Analyze the location of block source code
-
Through the
block
At the break point, analyze the runtimeblock
, open assembly -
add
objc_retainBlock
Symbol breakpoint, found will go to_Block_copy
-
add
_Block_copy
Symbol breakpoint, run to break, atlibsystem_blocks.dylib
In the source
You can download the latest version from Apple’s open source websitelibclosure-78Source code, by viewing_Block_copy
Source code implementation, foundblock
The real type at the bottom isBlock_layout
3 Block type: Block_layout
To viewBlock_layout
The definition of a type, yesA structure
-
Isa: Points to a class that indicates the block type
-
Flags: The flags identifier represents the additional information of some blocks in bits, similar to the bit fields in ISA. There are several types of flags. Focus on BLOCK_HAS_COPY_DISPOSE and block_has_signature. BLOCK_HAS_COPY_DISPOSE determines whether block_descriptor_2.block_has_signature is present Determines whether Block_descriptor_3 is present
- 1 a:
BLOCK_DEALLOCATING
, release flag, – commonBLOCK_NEEDS_FREE
做with
The operation is passed in togetherFlags
To inform theblock
Can release - 16:
BLOCK_REFCOUNT_MASK
, the storageThe value of the reference count
; Is an optional parameter - 24th:
BLOCK_NEEDS_FREE
, 16Indicates whether or not it is valid
The program decides based on itWhether to increase or decrease reference count bits
Value; - 25:
BLOCK_HAS_COPY_DISPOSE
, whether or notCopy helper function
(a copy helper function); - 26:
BLOCK_HAS_CTOR
, whether or notblock
Destructor; - 27th:
BLOCK_IS_GC
, indicating whether there is garbage collection; //OS X - 28:
BLOCK_IS_GLOBAL
Is the flag globalblock
; - 30th:
BLOCK_HAS_SIGNATURE
, andBLOCK_USE_STRET
In contrast, judge the presentblock
Whether you have a signature. Used forruntime
Time dynamic call
- 1 a:
-
Reserved: Reserved information. It can be understood that the reserved position is used to store information about internal variables of a block
-
Invoke: Is a function pointer to the block’s executing code
-
Descriptor: 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_1
Is choiceBlock_descriptor_2
和Block_descriptor_3
It’s all optional
About the abovedescriptor
The classification of can be reflected in its constructor, whereBlock_descriptor_2
andBlock_descriptor_3
Is throughBlock_descriptor_1
Address, pastTranslation memory
To get the
③.4 Block Memory changes
-
Interrupt point run, open assembly mode, go to
objc_retainBlock
.block
The breakpoint reads the registerx0
For the time of,block
isGlobal block
, i.e.,__NSGlobalBlock__
type -
Increase external
Variable a
And, inblock
printing
At this time to readblock
The breakpoint reads the registerx0
For the time of,block
isStack block
— __NSStackBlock__
-
Execute to symbol breakpoint
objc_retainBlock
,The stack area block
-
increase
_Block_copy
Symbol breakpoint and break, directly at the lastret
Add breakpoint, readx0
, discovered by_Block_copy
And then, it becomes thetaHeap block
, i.e.,__NSMallocBlock__
Mainly becauseblock
The address has been changed toHeap block
Call the situation
-
This can also be verified using breakpoints
-
register read x0
readx0
forHeap block
-
Further down,
register read x9
readx9
, orHeap block
-
To continue down
register read x11
In this case, it refers to a piece of memory space for storage_block_invoke
-
Hold down the
control + step into
And into the_block_invoke
, can be concluded is throughTranslation memory
To get theblock
Internal implementation
From the source code of the Block_layout structure mentioned above, it can be seen that there is an attribute called invoke, that is, the executor of the block, which is transferred to invoke from isa’s first address translation of 16 bytes, and then executes the call.
(3). 5
Go ahead, read the X0 register, look at the memory layout, and get the property descriptor Block_layout by translation 3*8, mainly to see if there is Block_descriptor_2 and Block_descriptor_3, Three of them have block’s signature
-
Register read x0, read register x0
-
Po 0x0000000280AD9Fb0 prints a block
-
x/8gx 0x0000000280ad9fb0
, that is, printblock
The memory of -
x/8gx 0x0000000100024010
To see thedescriptor
The memory condition of the third one0x0000000100023396
Said the signature -
Check whether Block_descriptor_2 is present, that is, whether BLOCK_HAS_COPY_DISPOSE (copy helper function) of flags has a value
p/x 1<<25
, i.e.,1 moved 25 to the left
, whose hexadecimal is0x2000000
p 0x02000000 & 0x00000000c1000002
, i.e.,BLOCK_HAS_COPY_DISPOSE & flags
Is equal to0
, means noBlock_descriptor_2
-
Check whether Block_descriptor_3 is present
-
P /x 1<<30, that is, 1 moves 30 bits to the left
-
p 0x40000000 & 0x00000000c1000002
, i.e.,BLOCK_HAS_SIGNATURE & flags
If there is a value, there isBlock_descriptor_3
-
p (char *)0x000000010089f395
– access toBlock_descriptor_3
The properties in thesignature
The signature -
po [NSMethodSignature signatureWithObjCTypes:"v8@?0"]
, that is, print the signature
The signature part is described as follows
// No return value
return value: -------- -------- -------- --------
type encoding (v) 'v'
flags {}
modifiers {}
frame {offset = 0, offset adjust = 0, size = 0, size adjust = 0}
memory {offset = 0, size = 0}
argument 0: -------- -------- -------- --------
//encoding = (@), type @?
type encoding (@) '@? '
//@ is isObject,? IsBlock stands for isBlockObject
flags {isObject, isBlock}
modifiers {}
frame {offset = 0, offset adjust = 0, size = 8, size adjust = 0}
// The offset is 8 bytes
memory {offset = 0, size = 8}
Copy the code
The block signature information is similar to the method signature information. It mainly shows the block return value, parameters, and types.
③.6 Block copy analysis for three times
③ 6.1 _Block_copy source code analysis
Enter the_Block_copy
Source,block
fromThe stack area
Copy toThe heap area
- If you need to release, release it directly
block
The reference count ofruntime
Dealt with, is by their own management- There might be a question here — why is the reference count +2 instead of +1?
- because
flags
The first position of theRelease tag
- If it is
globalBlock
, is not requiredcopy
, return directly - Instead, there are only two cases:
The stack area block
orHeap area block
Because ofHeap area block
Need to apply for space, there is no relevant code to apply for space, so it can only beThe stack area block
- through
malloc
Allocates memory space for receivingblock
- through
memmove
willblock
Copy the file to the newly obtained memory - Set up the
block
The object is of typeHeap area block
, i.e.,result->isa = _NSConcreteMallocBlock
- through
(3). 6.2 _Block_object_assign analysis
Want to analyzeblock
theThree layers of the copy
First, we need to know what kinds of external variables are in__block CPP file
Is passed when a function is declared__main_block_desc_0_DATA
Struct, it’s going to be called from inside__main_block_copy_0
The function,__main_block_copy_0
It will call_Block_object_assign
.
rightBlock modification
One of the most used isBLOCK_FIELD_IS_OBJECT
andBLOCK_FIELD_IS_BYREF
The _Block_object_assign method is called when external variables are copied in the underlying compiled code
Enter the_Block_object_assign
The source code
- 1. If it is a common object, submit it
ARC
Processing, andCopy object pointer
, i.e.,Reference count +1
, soExternal variables cannot be released
- 2. If it is
block
Type is passed_Block_copy
Operation,block
fromThe stack is copied to the heap
- 3. If it is
__block
Modify the variable called_Block_byref_copy
Function, performMemory copy
And routine treatment
At this point, the captured variable is__block
Modification of theBLOCK_FIELD_IS_BYREF
Type, is called*dest = _Block_byref_copy(object);
- 1. Forcibly convert the incoming object to
Block_byref
Structure type object, save a copy - 2. No external variables
Copy to the heap
, you need toApplication memory
, itsTo copy
- If it has already been copied, it is processed and returned
- Among them
copy
andsrc
theforwarding
Pointers arePointing to the same piece of memory
Is that why__block
Modification of theObject has the ability to modify
The reason why (*src2->byref_keep)(copy, src)
(*src2->byref_keep)(copy, src)
Follow it and you’ll find itBlock_byref
Structure comes whilebyref_keep
isBlock_byref
The firstfive
attribute
Code debugging
-
To define a
__block
Modification of theNSString
object -
The results of clang compilation are as follows
-
The compiled cj_name is more than the normal variable __Block_byref_id_object_copy_131 and __Block_byref_id_object_dispose_131
-
__Block_byref_cj_name_0
I have a lot of structures__Block_byref_id_object_copy
and__Block_byref_id_object_dispose
_Block_copy->_Block_byref_copy->_Block_object_assign, which corresponds to the above three-layer copy
So how did Block get cj_NAME?
- 1, through the
_Block_copy
Methods,block
Make a copy to the heap - 2, through the
_Block_object_assign
Method normal copy because__block
The external variables of the modifier are at the bottomBlock_byref
The structure of the body - 3, find the external variable also has an object, from
bref
To retrieve the corresponding objectcj_name
Copy toblock
Space, can be used (the same space can be used, different can not be used). Finally, through the memory translation is obtainedcj_name
For the time of,cj_name
And the outside worldcj_name
Is the same memory space (from_Block_object_assign
In the method*dest = object;
See)
To summarize, the three-layer copy of a block refers to the following three layers:
- [Layer 1] Through
_Block_copy
Implement a copy of the object itself, from the stack to the heap - [Second layer] Pass
_Block_byref_copy
Method to copy the object toBlock_byref
Structural type - [Third layer] call
_Block_object_assign
Methods,__block
Modifies a copy of the current variable
Note: Only__block
Modified object,block
thecopy
There are three layers only
(3). 6.3 _Block_object_dispose analysis
in__Block_byref_id_object_dispose_131
That’s called in the implementation_Block_object_dispose
Let’s see_Block_object_dispose
The underlying implementation of
From the source code, we can know that _Block_object_dispose is a release operation, and different release operations are carried out through blocks of different partitions. And _Block_object_assign does the retain operation.
- Enter the
_Block_byref_release
Source code, the main isRelease and destroy objects and variables
- Do nothing if it is a free object (auto-free)
- If it is
__block
Modification,Point the pointer back to the original area and free it with free
(3). 6.4 summary
block
Is the essence of__main_block_impl_0
Structure object, so it can be used% @
printblock
The statement just putsblock
The implementation is saved, and the specific function implementation is requiredTo call
block
When an external variable is capturedblock
Structure experienceAutomatically generate a property
To save the variable__block
The modified property generates the response structure underneath, holds a pointer to the original variable, and passes onePointer address to block
block
There are three copies in:Copies of the block
,Copy the memory address of the captured variable
,Copy the object
Block
The three layerscopy
The flow is shown in the figure below
Write in the back
Study harmoniously without being impatient. I’m still me, a different color of fireworks.