Comparison of classes and structures
Classes in swift:
class LLPerson { var age: Int var name: String init(_ age: Int, _ name: String) { self.age = age self.name = name } } var person = LLPerson(18, "LL") var person1 = person
Class is a reference type, person to person1 is the assignment of the pointer, and the contents pointed to by the pointer are consistent.
po: the difference between p and po is that using po will only output the corresponding value, while p will return the type of value and the reference name of the command result.
x/8g: read the value in memory (8g: output in 8-byte format)
The addresses of printed person and person1 are inconsistent, and the stored memory address is 8 bytes.
When creating a person object, allocate 8 bytes in the stack area, then allocate space in the heap area, put the value in the heap area, assign the pointer to person, and the pointer points to heap. You can use cat address xxx to view the pointer.
Structure in swift:
struct LLPerson { var age: Int var name: String init(_ age: Int, _ name: String) { self.age = age self.name = name } } var person = LLPerson(18, "LL") var person1 = person person1.age = 19 person1.name = "GG"
The structure is a value type. po prints the value. Modifying the value in person1 will not affect person.
For a class, you need to find the value in the heap through the pointer. The structure only needs to move the pointer on the stack.
Main similarities between structure and class:
- Define properties that store values
- Definition method
- Define subscripts to provide access to their values using subscript syntax
- Define initializer
- Use extension to expand functionality
- Follow the protocol to provide a function
Main differences:
- Classes have inherited properties, but structs do not
- Type conversion enables you to check and interpret the types of class instances at run time
- Class has a destructor to free its allocated resources
- Reference counting allows multiple references to a class instance
Can pass github upper StructVsClassPerformance This case is used to intuitively test the time allocation of the current structure and class.
Class initializer
The current class compiler does not automatically provide member initializers by default, but for structures, the compiler will provide default initialization methods (provided that we do not specify initializers ourselves)!
class LLPerson { var age: Int var name: String init(_ age: Int, _ name: String) { self.age = age self.name = name } convenience init() { self.init(18, "LL") } }
When creating instances of classes and structures in Swift, you must set an appropriate initial value for all storage properties. Therefore, the class LLPerson must provide the corresponding specified initializer. At the same time, we can also provide a convenient initializer for the current class (Note: the convenient initializer must call another initializer from the same class).
The portable initializer must call other initializers first, otherwise it will fail to compile and report an error. The property must be initialized when the property is accessed. For safety reasons.
Initializer rule:
- The specified initializer must ensure that all properties introduced by its class are initialized before delegating to the parent class initializer.
- The specified initializer must delegate the parent class initializer up before setting new values for inherited properties. If this is not done, the new value given by the specified initializer will be overwritten by the initializer in the parent class.
- The convenience initializer must first delegate other initializers in the same class, and then assign new values to any property (including the properties defined in the same class). If this is not done, the new values assigned by the convenience initializer will be overwritten by other specified initializers in its own class.
- Before the first stage initialization is completed, the initializer cannot call any instance method, read the value of any instance property, or reference self as a value.
Failable initializer:
class LLPerson { var age: Int var name: String init?(_ age: Int, _ name: String) { if age < 18 {return nil} self.age = age self.name = name } convenience init?(_ age: Int) { self.init(18, "LL") } }
In this Swift, the failable initializer writes a return nil statement to indicate under what circumstances the failable initializer will trigger an initialization failure.
Necessary initializers:
Add the required modifier before the class initializer to indicate that all subclasses of the class must implement the initializer.
Class lifecycle
Swift is compiled into IR by swift compiler, and then generates executable files.
Analysis output AST
swiftc main.swift -dump-parse
//Analyze and check the type output AST
swiftc main.swift -dump-ast
Generated intermediate language (SIL), not optimized
swiftc main.swift -emit-silgen
Generated intermediate language (SIL), optimized
swiftc main.swift -emit-sil
Generate LLVM intermediate language (. ll file)
swiftc main.swift -emit-ir
Generate LLVM intermediate language (. bc file)
swiftc main.swift -emit-bc
Generate assembly
swiftc main.swift -emit-assembly
Compile to generate executable out file
swiftc -o main.o main.swift
You can use swiftc - emit SIL ${srcroot} / llswifttest / main swift > ./ main. sil & open main. SIL generate SIL file:
class LLPerson { var age: Int = 18 var name: String = "LL" }
class LLPerson { @_hasStorage @_hasInitialValue var age: Int { get set } @_hasStorage @_hasInitialValue var name: String { get set } @objc deinit init() }
SLL files can be referenced https://github.com/apple/swift/blob/main/docs/SLL.rst.
Swift object memory allocation:
__allocating_init -----> swift_allocObject -----> swift_allocObject -----> swift_slowAlloc -----> Malloc
The memory structure HeapObject (OC objc_object) of Swift object has two attributes: Metadata and RefCount. By default, it occupies 16 bytes.
After accessing the source code, the following structure can be obtained:
Class structure:
struct HeapObject { //Custom class structure var metaData: UnsafeRawPointer var refcounted1: UInt32 var refcounted2: UInt32 } class LLPerson { var age: Int = 18 var name: String = "LL" } var person = LLPerson() let objcRawPtr = Unmanaged.passUnretained(person as AnyObject).toOpaque() //Get object pointer let objcPtr = objcRawPtr.bindMemory(to: HeapObject.self, capacity: 1) //Rebind print(objcPtr.pointee)
metadata structure:
struct Metadata { //metadata structure var kind: Int var superClass: Any.Type var cacheData: (Int, Int) var data: Int var classFlags: Int32 var instanceAddressPoint: UInt32 var instanceSize: UInt32 var instanceAlignmentMask: UInt16 var reserved: UInt16 var classSize: UInt32 var classAddressPoint: UInt32 var typeDescriptor: UnsafeMutableRawPointer var iVarDestroyer: UnsafeRawPointer } let metadata = objcPtr.pointee.metaData.bindMemory(to: Metadata.self, capacity: MemoryLayout<Metadata>.stride).pointee print(metadata)