Initial classes and structs
class
&& (class)struct
(Structure)
Class:
class LGTeacher{
var age: Int
var name: String
init(age: Int, name: String) {
self.age = age
self.name = name
}
}
Copy the code
Struct:
struct LGTeacher{
var age: Int
var name: String
}
Copy the code
Structs and classes are essentially the same
- Defines attributes that store values
- Define methods
- Define subscripts to provide access to their values using subscript syntax
- Define initializers
- Use Extension to extend functionality
- Follow a protocol to provide a function
Major differences
- Classes have inherited properties that structs do not
- Type conversions enable you to examine and interpret the type of a class instance at run time
- A class has a destructor that frees its allocated resources
- Reference counting allows multiple references to a class instance
Classes are reference types
- Classes are reference types. This means that a variable of a class type does not store the specific instance object directly, but rather refers to the memory address where the specific instance is currently stored.
class LGTeacher{
var age: Int
var name: String
init(age: Int, name: String) {
self.age = age
self.name = name
}
}
var t = LGTeacher.init(age: 18, name: "joker")
var t1 = t
Copy the code
There are two instructions to view the memory structure of the current variable
Po: The difference between p and Po is that Po only prints the corresponding value, while p returns the type of the value and the reference name of the command result. X /8g: Read the value in memory (8g: output in 8-byte format)
Struct is a value type
Value types, most typically structs, store concrete instances (or concrete values), whereas class types store addresses in variables.
Specific examples are as follows:
struct LGTeacher{
var age: Int
var name: String
}
var s = LGTeacher.init(age: 18, name: "joker")
var s1 = s
Copy the code
Run the LLDB command to view the address information
Reference type (class) and Value type summary (struct)
- The reference type is the equivalent of Excel online, and when the link is shared with others, their changes are visible to us
- The value type is like a local Excel, and when we pass our local Excel to someone else, we’re just copying it back to someone else,
- Generally, value types are stored on the Stack and reference types are stored on the Heap. Read/write speed: Stack > Heap
Structs are preferred for entities that do not need inheritance during development.
Basic concepts of memory regions
- Stack: The context in which local variables and functions are run
- Heap: Stores all objects
- Global: Stores Global variables. Constant; Code section
- Segment & Section: A Mach-o file has multiple segments, each with a different function. Each Section is then divided into smaller sections
-
TEXT. TEXT: machine code
-
Text. cstring: hardcoded string
-
Text. const: initialized constant
-
Data. DATA: variable (static/global) DATA initialized. Const: constant that has not been initialized
-
Data.bss: uninitialized (static/global) variable
-
DATA.common: Symbol declaration that is not initialized
-
Stack (stack) instance view
class LGPerson { var age = 18 var name = "joker" } struct LGTeacher{ var age = 18 var name = "Kody" var p = LGPerson() } func test(){ var t = LGTeacher() print("end") } test()Copy the code
LLDB debugging uses commands
frame varibale -L xxx
Copy the code
Run cat address 0xxxxxxxxx to view the current zone location.
liblgcataddress.dylib
- T: On the Stack
- P in T: on the Heap
View Heap instances
Class LGTeacher{var age = 18 var name = "Kody"} func test(){ Var t = LGTeacher() print("end")} test()Copy the code
LLDB debugging
- On stack: open 8 bytes
- Find the appropriate memory area on the heap space
- The value – > pile
- The memory address on the stack points to the heap area
You can intuitively test the time allocation of current structures and classes by using StructVsClassPerformance on Github.
Class initializer
Current class compilers do not automatically provide member initializers by default, but they do provide default initializers for structures (if we don’t specify initializers ourselves)!
Instances of classes and structures in Swift must be created with an appropriate initial value for all storage properties.
Structures write properties directly, without writing init initializer methods
The compiler provides a default initialization method
struct LGTeacher{
var age: Int
var name: String
}
var t = LGTeacher.init(age: 18, name: "joker")
Copy the code
Class initializer
1. The specified initializer must be provided:init()
class LGTeacher{
var age: Int
var name: String
init(age: Int, name: String) {
self.age = age
self.name = name
}
}
var t = LGTeacher.init(age: 18, name: "joker")
Copy the code
2. Convenient initializer:convenience init()
Convenient initializer calls
class LGTeacher{
var age: Int
var name: String
init(age: Int, name: String) {
self.age = age
self.name = name
}
convenience init() {
self.init(age: 18, name: "joker")
}
convenience init(_ age: Int) {
self.init(age: age, name: "joker")
}
convenience init(_ name: String) {
self.init(age: 18, name: "joker")
}
}
var t = LGTeacher.init();
Copy the code
Note: The convenience initializer must call another initializer from the same class.
When using a convenient initializer, assign a value to a variable after calling another initializer. Current object not initialized, access does not exist!
When using a convenient initializer with derived subclasses, note the following:
- The specified initializer must ensure that all attributes introduced by its class are initialized before delegating up to the parent class initializer.
- The specified initializer must delegate to the parent initializer before it can set new values for inherited properties. If you do not, the new value assigned by the specified initializer will be overwritten by the initializer in the parent class
- The convenience initializer must first delegate to other initializers in the class before assigning new values to any properties (including those defined in the class). If this is not done, the new value assigned by the convenience initializer will be overwritten by other specified initializers in its class.
- The initializer cannot call any instance methods, read the values of any instance attributes, or refer to self as a value until the first phase of initialization is complete.
class LGPerson{ var age: Int var name: String init(age: Int, name: String) { self.age = age self.name = name } convenience init(_ age: Int) { self.init(age: age, name: Class LGTeacher: LGPerson {var subjectName: String init(_ subjectName: String) { self.subjectName = subjectName super.init(age: 18, name: "joker") } }Copy the code
3. Failable initializer
The initialization failed because the parameters were invalid or external conditions were not met. Procedure Such Swift failable initializers write return nil statements to indicate under what circumstances the failable initializers trigger initialization failures.
class LGPerson{ 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(age: age, name: "joker") } }Copy the code
Condition age less than 18, returns nil, failure initializer
4. Required initializers
Add the required modifier before the class initializer to indicate that all subclasses of the class must implement the initializer
class LGPerson{ var age: Int var name: String required init(age: Int, name: String) self.age = age self.name = name } convenience init(_ age: Int) { self.init(age: age, name: Class LGTeacher: LGPerson {var subjectName: String init(_ subjectName: String) { self.subjectName = subjectName super.init(age: 18, name: "joker") } required init(age: Int, name: String) { fatalError("init(age:name:) has not been implemented") } }Copy the code
Class life cycle
The iOS development language OC and Swift backends are compiled with LLVM.
- OC is compiled by the CLang compiler into IR, which is then regenerated into the executable.o(in this case, our machine code).
- Swift is compiled into IR by Swift compiler and then generates executable files.
Swiftc main. Swif-dump-parse // Analyze and check the type of output AST swiftc main. Swif-dump-ast // generate intermediate language (SIL), Swiftc main. Swift - EMIT - Silgen // Generate intermediate Language (SIL) Swift-emit -sil // Generates LLVM intermediate language (.ll file) swifTC main. Swift-emit -ir // generates LLVM intermediate language (.bc file) swifTC Swift -emit-assembly // Compilation generates executable. Out file swiftc-o main.o main.swiftCopy the code
Generate intermediate language (SIL) by embedding the following script:
swiftc -emit-sil ${SRCROOT}/LGSwiftTest/main.swift > ./main.sil & open main.sil
Copy the code
- @main: entry function
- %0/%1/%2: register, virtual
- Alloc_global: Allocates global variables
- Xcrun swift-DEMANgle: Restores the obfuscated names
- %3 = global_addr @$s4main1tAA9LGTeacherCvp: global variable address -> %3
- %4 = metatype $@thick LGTeacher.Type: Obtain the mettype of LGTeacher
- %5 = function_reflgteach.__allocating_init () : function reference
- %6 = %5(%4) : $@convention(method): apply %5(%4) to %6
- Store %6 to %3: $*LGTeacher: store the current %6 to %3
Swift source object memory allocation:
_ _allocating_init
–>swift_allocObject
–>_swift_allocObject_
–>swift_slowAlloc
–>Malloc
- The HeapObject (OC objc_object{ISA}) memory structure of the Swift object has two properties: Metadata and RefCount, occupying 16 bytes by default.
The Metadata structure:
struct Metadata{
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
}
Copy the code
View the => Metadata structure through the data structure of the class
struct HeapObject{ var metadata: UnsafeRawPointer var refcounted1: UInt32 var refcounted2: UInt32 } class LGTeacher{ var age: Int = 18 var name: String = "Joker"} var t = LGTeacher() // Let objcRawPtr = Unmanaged. PassUnretained (t as) Let objcPtr = objCrawptr. bindMemory(to: heapObject. self, capacity: Print (objcptr.pointee) print(objcptr.pointee MemoryLayout < Metadata >. Stride size measurement data pointer let Metadata. = objcPtr pointee. Metadata. BindMemory (to: Metadata. Self, capacity: MemoryLayout<Metadata>.stride).pointee print(metadata) print("end")Copy the code
The output is: