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

  1. Defines attributes that store values
  2. Define methods
  3. Define subscripts to provide access to their values using subscript syntax
  4. Define initializers
  5. Use Extension to extend functionality
  6. Follow a protocol to provide a function

Major differences

  1. Classes have inherited properties that structs do not
  2. Type conversions enable you to examine and interpret the type of a class instance at run time
  3. A class has a destructor that frees its allocated resources
  4. 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)

  1. The reference type is the equivalent of Excel online, and when the link is shared with others, their changes are visible to us
  2. 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,
  3. 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

  1. Stack: The context in which local variables and functions are run
  2. Heap: Stores all objects
  3. Global: Stores Global variables. Constant; Code section
  4. 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

  1. On stack: open 8 bytes
  2. Find the appropriate memory area on the heap space
  3. The value – > pile
  4. 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:

  1. The specified initializer must ensure that all attributes introduced by its class are initialized before delegating up to the parent class initializer.
  2. 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
  3. 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.
  4. 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.

  1. OC is compiled by the CLang compiler into IR, which is then regenerated into the executable.o(in this case, our machine code).
  2. 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

  1. @main: entry function
  2. %0/%1/%2: register, virtual
  3. Alloc_global: Allocates global variables
  4. Xcrun swift-DEMANgle: Restores the obfuscated names
  5. %3 = global_addr @$s4main1tAA9LGTeacherCvp: global variable address -> %3
  6. %4 = metatype $@thick LGTeacher.Type: Obtain the mettype of LGTeacher
  7. %5 = function_reflgteach.__allocating_init () : function reference
  8. %6 = %5(%4) : $@convention(method): apply %5(%4) to %6
  9. 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: