Series of articles:OC Basic principle series.OC Basic knowledge series.Swift bottom exploration series.IOS Advanced advanced series
preface
I originally planned to talk about the content of dynamic library in this article, but due to the recent busy project, so I decided to write some content about Swift, interested students can have a look. This article focuses on why structs are value types and classes are reference types
Value types
Prerequisite: You need to know about the five areas of memory, you can refer to this articleMemory management (MEMORY partition), as shown in the figure below:
- The stack address is larger than the heap address
- The stack is from
High address -> low address
, extending downward fromsystem
Automatic management is a piece of continuous memory space - The heap is from
Low address -> high address
, extending upward bydevelopers
Management, heap space structure is similar toThe list
, it isdiscontinuous
the - In daily development
The overflow
Refers to theStack overflow
, can be understood as the collision of stack and heap boundaries Global area, constant area
Are stored in theMach-O
In the__TEXT cString
Period of
Let’s use an example to introduce what is a value typeAs you can see from the example, age is stored on the stack
- To view
age
Memory condition, as can be seen from the figure, stack areaDirect memory
isvalue
- Get stack address of age:
po withUnsafePointer(to: &age){print($0)}
- Age memory:
x/8gx 0x00007ffeefbff530
- Get stack address of age:
- To view
age1
As can be seen from the graph below,age1
The assignment ofage
Take the value of, and assign it toage1
. Among themThe age and age1
The address of the8 bytes
It can be explained hereStack space is continuous
, and isFrom high to low
the
So age is the value type
Value type characteristics
- 1. Yes is stored in the address
value
- 2. Value type transfer process, equivalent to
pass
aA copy of the
That’s what’s calledDeep copy
- 3.
Value passed
Process, andUnshared state
The structure of the body
The usual way of writing a structure
In structs, compilation does not report errors if you do not give default values to attributes. That is, a property may or may not be assigned in a structure
Why are structs value types
Define a structure and analyze it
Print t: Po t, as can be seen from the figure below, the print of t is the value directly, without any information related to the address
- Get t’s memory address and view its memory
- Obtain address:
po withUnsafePointer(to: &t){print($0)}
- Check memory:
x/8gx 0x0000000100003050
- Obtain address:
Question: If t is assigned to T1, will t change if T1 is changed?
- Print t and T1 directly, and you can see that t does not change because t1 changes, mainly because
T1 and t
Is betweenValue passed
, that t1 and T are different memory space, is directlyt
In theCopy the value
tot1
In the.T1 Changed memory space
, it isIt doesn't affect the memory space of T
the
SIL verification
Similarly, we can verify that a structure is a value type by analyzing SIL
- in
SIL
In the file, we look at the initialization method of the structure, and we can seeOnly the init
And theThere is no malloc
In which there is no allocation of heap areas
conclusion
Structs are value types
And the address of the structure is the memory address of the first member- Value types
- Directly in memory
Stored value
- An assignment of a value type is a
Value passed
“, which is equivalent to a copy of a copy, into different memory space, two Spaces with each otherUnshared state
Value passed
In fact, isDeep copy
- Directly in memory
Reference types
class
- The common way to write class
- In a class, if the attribute is not assigned and is not optional, the compilation will report an error
- You need to implement it yourself
init
methods
Why are classes reference types?
Define a class, illustrated by an example
Class initialization object T, stored in the global area
- print
S, t
As can be seen from the picture,s
What’s in memory space isaddress
.t
Is stored invalue
- Gets the address of the S variable and looks at its memory
- To obtain
s
Pointer address:po withUnsafePointer(to: &s){print($0)}
- Query s global address memory:
x/8gx 0x0000000100003240
- Query the heap address memory stored in s address:
x/8gx 0x0000000100677c70
- To obtain
Characteristics of reference types
- 1. Yes is stored in the address
The heap area address
- 2.
The heap area address
Is stored invalue
Q 1: If t1 is assigned to T2, will t1 be changed if T2 is changed?
According to LLDB debugging, changing T2 will cause T1 to change, mainly because the same heap address is stored in BOTH T2 and T1 addresses. If the same heap address is changed, changing T2 will cause T1 to be changed at the same time, that is, the shallow copy
Q 2: If the structure contains class objects, will t change if the instance object properties in T1 are modified?
As can be seen from the printed result, if the attributes of the instance object in T1 are modified, the attributes of the instance object in T will change. Although the value is passed in the structure, the address is still passed in the teacher because it is a reference type
This can also be verified by LLDB debugging
- Print the address of T:
po withUnsafePointer(to: &t){print($0)}
- Print the memory of t:
x/8gx 0x0000000100008380
- Print the memory situation of teacher address in T:
x/8gx 0x0000000106210be0
Note: When writing code, you should tryAvoid value types containing reference types
View currentSIL
Documents, althoughLjTeacher
It’s in the value type, and in passing, whether it’s passing or assigning,teacher
This is theReference counting
administrated You can printstudent
To verify our statement, where student’s reference count is3
Mainly because:
main
In theretain
At a timestudent.getter
methodsretain
At a timestudent.setter
In the methodretain
At a time
mutating
Define a stack through the structure, mainly push, pop methods, we need to dynamically modify the stack array
- If the following method is used, an error will be reported directly because
The value type itself is not allowed to modify attributes
the
- Change the push method to the following and check
SIL
In the filepush
function
As can be seen from the figure, in addition to item, the push function also has a default parameter, self, which is of let type, indicating that modification is not allowed
- Try 1: If I change the push function to look like this, can I add it?
The print result is as followsYou can derive the code union aboveCannot add item
Because theS is another structure object
, which is equivalent toCopy the value
, then callPush is an array that adds item to S
In the
- Add push to push based on the previous error
mutating
Found ready to add to array
- Look at its SIL file, find the push function, and see that it’s different,
push
addmutating
After (only for value types) is essentially givenValue type function
addedinout
Keyword, equivalent to in the process of value passing,pass
isreference
(i.e. address)
Inout keywords
In general, the default parameters in the function declaration are immutable. If you want to change them directly, you need to add the inout keyword to the parameters
- without
inout
Keyword, assign value to parameter, compile error
- add
inout
Keyword that can be assigned to parameters
conclusion
- 1. If you want to modify the properties of a function in a structure, add the prefix to the function
mutating
Class does not - 2.
mutating
Essentially plus oneInout modifies self
- 3.
Inout
The equivalent ofTake the address
Can be understood asaddress
That reference - 4.
mutating
modifiedmethods
And theinout
modifiedparameter
conclusion
View the memory model of struct & class with LLDB.
value
Type, equivalent to oneThe local file
When we send you a file over the network, it’s like a value type, what did you change that we don’t knowreference
Type, equivalent to oneOnline file
When we edit a file with you, it acts as a reference type and both sides see the changesThe structure of the body
In theFunction modifies attributes
, need to be added before the functionmutating
Keyword, essentially adding the default argument self to the functioninout
Keyword, willself
fromlet
The constant is changed tovar
variable
Method dispatch
From the above analysis, we have the following question: Where are the methods of structs and classes stored? Let’s analyze them one by one
Static distributed
The function of a value object is called statically, that is, directly from the address, calling a function pointer, which is determined after compilation and linking. The function pointer is stored in the code snippet, while the structure does not hold methods. So it can be called directly from the address
- Struct function debugging is shown below
- Open Open the demo
Mach-O
Executable file, of which__text
Segments, called code segments, are where the assembly instructions that need to be executed are
- There is a problem with the above analysis: the direct address call is followed by
symbol
Where did this symbol come from?
fromMach-O
In the fileSymbol Tables
, butStrings are not stored in symbol tables
, the string is stored inString Table (a list of strings containing all variable and function names, stored as strings)
, and then search for the corresponding character in the string according to the offset value in the symbol table, and then rename the character:Project name + class name + function name
, as shown below
Symbol Table
: The location of the stored symbol in the string tableDynamic Symbol Table
:Dynamic library function
Offset information in the symbol table
You can also obtain the symbol table in the project through the terminal command nm
- View the symbol table:
Nm Mach-o file path
- Restore symbol names by command:
Xcrun swift - demangle symbols
- If you have
edit scheme -> run
In thedebug
torelease
, in the executable directory, an additional suffix isdSYM
In this case, go to the Mach-o fileteach
, found to be unable to find, the main reason is becauseStatically linked functions, in fact, do not need symbols
Once the compilation is complete, its address is determined after the current oneThe symbol table deletes the symbol corresponding to the current function
, in the release environment,The symbol table
Is stored inCould not determine the symbol of the address
- For symbols that cannot determine the address, it is in
Runtime determination
When the function is called for the first time (equivalent toLazy loading
), for example print, is passeddyld_stub_bind
addressable
Function symbol naming rules
- for
C functions
(C does not allow function overloading because there is no way to tell the difference)
- In the case of OC, function overloading is also not supported, and its symbolic naming is
-[class name function name]
- For Swift, yes
Function overloading
Mainly because of swiftRenormalization naming rule
It’s a little bit complicated, yesMake sure the function symbol is unique
Dynamic dispatch
Assembly instruction supplement
blr
: jump instruction with return, jump to instruction followed by address saved in registermov
: Copy a value from one register to another register (used only between registers or between registers and constants, not memory addresses)- Mov x1, x0 copies the value of register x0 into register x1
ldr
: Reads a value from memory into a register- LDR x0, [x1, x2] add register x1 and register x2 as the address, take the value of the memory address into register X0
str
: Writes a value in a register to memory- STR x0, [x0, x8] saves the value of register x0 to memory at [x0 + x8]
bl
: Jumps to an address
Explore the scheduling of classes
First, the format of V_Table in SIL files
Decl ::= sil-vtable // Sil Vtable contains keywords, identifiers (i.e. class names), all methods sil-vtable ::= 'sil_vtable' identifier '{' Sil-vtable-entry * '}' // The method contains the declaration and function name sil-vtable-entry ::= sil-decl-ref ':' SIL-linkage? sil-function-nameCopy the code
For example, in the case of LjTeacher, the V-tabler in SIL is shown in the figure below
sil_vtable
Key words:LjTeacher
: represents the function table of the LjTeacher class- Second, the declaration of the current method corresponds to the name of the method
- The table of functions can be interpreted as
An array of
Declare a method inside a class without any keyword modificationContinuous deposit
In our current address space. This point can be verified by the breakpoint
register read/x rax
For the time of,Address is the same as the address of the instance object
, includingrax
The address of the instance object, the first address
- If you look at the offset addresses of the following methods, you can find that the methods are stored consecutively and correspond exactly
V-Table
In the function tableDischarge of the order
, that is, in the order defined in the table of functions
Function table source exploration
Let’s explore the source code at the bottom of the function table
- Source search
initClassVTable
, and add breakpoints, and then write source code for debugging
It is encoded internally by the for loop, and offset+index is offset. Then method is obtained and stored in the offset memory, from which we can verify that the function is continuously stored
For functions in class, class method scheduling is via v-taable, which is essentially a contiguous memory space (array structure).
Question: What if you change the location of the method declaration? For example, the function in Extension, is the function scheduling mode still function table scheduling?
Verify with the following code
- To define a
The extension of LjTeacher
- Defining a subclass
LjYoungTeacher is inherited from LjTeacher
To view the V-table in the SIL
- To view
SIL
File, foundSubclasses inherit only the functions defined in class
, the function in the function table
If the extension function is also in the function table, it means that the subclass also has the function table, but the subclass can not have the related pointer to record whether the function is the parent class method or the subclass method. So you don’t know where to insert the method, so functions in Extension can’t be safely put into subclasses. Therefore, it can be proved that the method in Extension is called directly and belongs only to the class, and the subclass cannot inherit
Development considerations
- Inheriting methods and properties,
Can't write the extension
In the. - while
extension
The function created in the., must belong to its own class, but itsSubclasses also have access
, justCannot inherit and overwrite
, as shown below
Final, @objc, dynamic modifier functions
The final modification
final
The way to modify it isDirect dispatching
Can be verified by SIL validation + breakpoint validation
@ objc modification
use@objc
The key word is willswift
The method in is exposed to OCFound through SIL+ breakpoint debugging@objc
The way to modify it isFunction table scheduling
【 Tips 】 :mixed
Header file viewing mode: ViewThe project name - Swift. H
The header file
- OC still wouldn’t be able to call swift if it was just using the @objc modifier, so if you wanted to
OC access swift
Class requires inheritanceNSObject
The dynamic modification
Take the following code as an exampledynamic
Modifies how a function is scheduledWherein, the scheduling of teach function isFunction table scheduling
, can be verified through breakpoint debugging, usingdynamic
It means yesThe dynamic change
, meaning that classes can be used when they inherit from NSObjectmethod-swizzling
@objc + dynamic
Through breakpoint debugging, go isobjc_msgSend
Flow, movingState message forwarding
Scenario: Implement method exchange in SWIFT
- Before functions that need to be swapped in Swift
dynamic
Modify, and then pass:@_dynamicreplacement (for: function symbol)
Swap, as shown below
Replace the Teach method with Teach 5
- If teach is not implemented/if removed
dynamic
Modifier, an error is reported
conclusion
struct
isvalue
Type, where the function scheduling belongs toDirect call address
, i.e.,The static scheduling
class
isreference
Type in which function scheduling is passedV - Table function Table
For scheduling, i.eDynamic scheduling
extension
The function scheduling mode inDirect dispatching
final
The modified function scheduling mode isDirect dispatching
@objc
The modified function scheduling mode isFunction table scheduling
Class must also be used if OC is requiredInheritance NSObject
dynamic
The scheduling mode of the modified function isFunction table scheduling
To make the function dynamic@objc + dynamic
Combinatorial modification of function scheduling that is performed isobjc_msgSend
Process, i.e.,Dynamic message forwarding
Wrote last
The next article continues to write high order advanced series, introduces the content of dynamic library, the following will be based on the project to talk about dynamic library merge and other content, Swift article will be a supplement when the project is busy, because Swift does not have so many complex operations, also need not write shell language! Welcome everyone to leave a comment, also hope you like a lot of support. I hope we can communicate with each other, explore and make progress together