-
block
Introduction to theA 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.
-
block
type-
__NSGlobalBlock__
Global block, stored in a global areaLet’s start with the following codeDiscovery is simply a declaration
block
.block
No entry, no entryblock
The internal code block is simply printed without reference to external variablesblock
Type is__NSGlobalBlock__
-
__NSStackBlock__
The stack area blockThis is the type before the outside variable is processed
__NSStackBlock__
After the external variables are processed, the underlying values will beblock
Copy 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 ofMRC
You 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
__weak
modifiedblock
Not without strong referencescopy
So it’s printed at this pointblock
Or the stack areablock
-
__NSMallocBlock__
Heap area blockThe stack area
block
The bottom copy then becomes the heap areablock
-
-
block
nature-
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_0
The address of the function assigned toblock
Now let’s see__main_block_impl_0
The structure of the You can see it hereblock
The essence is actually a structure, and there is in the structureisa
You can also sayblock
It 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 calledFuncPtr
And willblock
Passed as an input parameter
-
-
block
How to capture variablesI wrote a simple block with no input and no external variables, and I wrote another block that uses external variables
block
Look at the bottom layerblock
Define a variable a in the outside world, print a in the code block, and see the compiled code:-
conclusion
Find the underlying
block
There 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
-
-
__block
The principle ofblock
The direct modification outside the code block is not used__block
Returns the following error when modifying a variableNow we’re using__block
The modifier found that no errors were reported and the modification succeededView the compiled code through ClangDiscovery after compilationa
This is where the address is not just a simple numeric value and is converted to__Block_byref_a_0
typeDiscovered by compiled code__Block_byref_a_0
It’s a structure, and thenblock
We also have one more structure__Block_byref_a_0
Type of pointer so low-levela
It’s a copy of the pointer to the outside worlda
The variable refers to the same piece of memory address, so it is used in this case__block
The modified variable can be successfully modified -
block
True typeBlock_layout
-
Find the block’s true type through code debugging
Discover the first declaration by assembly trace
block
The first thing you will do is go toobjc_retainBlock
Go to the figure belowNow we go to the next sign breakpointobjc_retainBlock
And found thatobjc_retainBlock
Method will jump to_Block_copy
Method, the break point continues down and finds the first entrylibobjc.A.dylib
In the library_Block_copy
Method, inside the method, there’s another jump_Block_copy
Method, same continue to follow the discovery intolibsystem_blocks.dylib
In the library_Block_copy
Method, at this point we find the source codeblock
The true type offoundblock
The true type ofBlock_layout
-
Block_layout
The source code to exploreThrough the source code found that the bottom is a structure as shown in figure
flags
identification- 1 a –
BLOCK_DEALLOCATING
, release flag, – commonBLOCK_NEEDS_FREE
Do bits and operations, passed in togetherFlags
To inform theblock
Can be released. - 16 – lower
BLOCK_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 notblock
Destructor; - 27th, indicating whether there is garbage collection; //OS X
- 28 –
BLOCK_IS_GLOBAL
Is a global block; - 30th –
BLOCK_HAS_SIGNATURE
, andBLOCK_USE_STRET
In contrast, judge the presentblock
Whether you have a signature. Used forruntime
Is dynamically called.
descriptor
Description:
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 ofBlock_descriptor_1
Is choiceBlock_descriptor_2
和Block_descriptor_3
It’s all optional
Take a look at
Block_descriptor_2
andBlock_descriptor_3
Constructor ofFound throughBlock_descriptor_1
The memory address of the - 1 a –
-
-
block
Three-layer copy analysisNote: 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 be
block
Copy from stack to heapSource code is relatively simple, mainly divided into the following steps- First check whether the input parameter is null and return null
- judge
block
Whether to release, do not copy - Check whether it is global
block
If yes, do not copy - Finally, the stack block, the first step is to create memory space
- And then there’s memory copy, which will
aBlock
Copy toresult
- The last is a simple assignment and return
result
-
Layer 2 Copy
_Block_byref_copy
Mainly for external variables
__block
I’m going to copy it when I modify itBlock_byref
The structure is from below_Block_object_assign
Source analysis knows if it is__block
The decorated object is given_Block_byref_copy
We’ll see at this point_Block_byref_copy
The source ofFrom the source can see why to use__block
Modify the variable inblock
Can directly modify the corresponding value, I look at the compiled codeFound in__block
Modified object converted to__Block_byref_person_0
Type to see__Block_byref_person_0
The structure of the bodyI found two extra functions__Block_byref_id_object_copy
and__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_byref
The structure of the bodyFound a common oneBlock_byref
I don’t have these two functions in my structure, butBlock_byref_2
There happen to be two functionscopy
anddispose
And then look at_Block_byref_copy
Function source found if presentcopy
anddispose
Method will be calledcopy
methodsBack to the compiled codecopy
The implementation of theDiscovery is called again_Block_object_assign
Method, 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_0
and__main_block_dispose_0
The implementations inside the method call, respectively_Block_object_assign
and__main_block_dispose_0
, can also know the source code of the two methods corresponding toBlock_descriptor_2
In thecopy
anddispose
Now let’s see_Block_object_assign
Source code implementationThere are three main steps for discovery through source code- Determine if it is a simple common object type and hand it over to ARC
- If the type is block, it is given
_Block_copy
To deal with - If the object is decorated with __block
_Block_byref_copy
The source code analysis of this method can be seen
-
-
block
A 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 one
block
And then there’s a propertyname
If theblock
The use ofname
And so onblock
Will have only the current object (which was also analyzed above,block
The 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 simple
block
Is required to useself
Property directly used in__weak
This will do, so that both Pointers point to the same memory address but use__weak
The modifier does not increment the reference count by one. - If it is
block
nestedblock
In 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
__weak
To embellish, but in the first oneblock
It’s in use__strong
To modify. Should be__strong
The modified variable is a local variable in the code block, soblock
The code is automatically released after execution, so there is no circular referenceblock
In the use__strong
Modified? Mainly because of the insideblock
Is a delayed operation if not used__strong
Modifier then completes the destructorweakSelf
It becomesnil
So in the nestedblock
I got it inweakSelf
Nil, that’s what we’re using__strong
In order to prolongweakSelf
Declare the cycle so that it is nested inblock
Destroy them after completion of execution
- If it’s simple
- __block decorates a variable
use__block
Retouching is used inblock
Internally you can modify the value of a variable’s attribute, as well as in the definitionblock
whenself
The reference count is incremented by one, but the variable can be set to 0 after the use is completenil
, thenself
The 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 pointself
It 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
OC
Is a single inheritance only language, but it is based on the runtime mechanism, so it can passNSProxy
To realize pseudo-multiple inheritance and fill the blank of multiple inheritanceNSProxy
和NSObject
It’s a sibling class, or a virtual class, but it’s implementedNSObject
The agreementNSProxy
A 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
- **__weak and __strong combine **
-