The structure of the body

  • In the Swift standard library, the vast majority of exposed types are structures, while enumerations and classes make up only a small portion

Common types such as Bool, Int, Double, String, Array, and Dictionary are all structures

struct Date {
    var year: Int
    var month: Int
    var day: Int
}
var date = Date(year: 2020, month:02, day:29)// The compiler automatically generates an initializer for the structure
Copy the code

  • All structures have an initializer automatically generated by the compiler (initializer, initializer, constructor, constructor)

In line ⑥, you can pass in all the member values to initialize all the members.


Initializer for a structure

The compiler may generate multiple initializers for a structure, depending on the situation,The purpose is to ensure that all members have initial values and that the code is safeTake a look at the following scenarios where an error is reported because a member variable is not initialized This way, there is no problem

struct Point {
    var x: Int = 0
    var y: Int = 0
}
var p1 = Point(x: 10, y: 10)
var p2 = Point(y: 10)
var p3 = Point(x: 10)
var p4 = Point(a)Copy the code

Let’s do another scene

struct Point {
    var x: Int?
    var y: Int?
}
var p1 = Point(x: 10, y: 10)
var p2 = Point(y: 10)
var p3 = Point(x: 10)
var p4 = Point(a)Copy the code

Because var x: Int? var y: Int? After the declaration, there is an initial value of nil by default, so the above error is not reported


Custom initializers

Once you define an initializer when defining a structure, the compiler does not automatically generate other initializers for it


Peep into the nature of the initializer

Here is the equivalent code at both ends. The first section uses the system-generated no-parameter initializer, and the second section uses our custom no-parameter initializer

struct Point {
    var x: Int = 0
    var y: Int = 0
}
var p = Point(a)Copy the code
struct Point {
    var x: Int
    var y: Int
    init(a) {
        x = 0
        y = 0}}var p = Point(a)Copy the code

Let’s take a look at their assembly code

func testStruct(a) {
    struct Point {
        var x: Int = 0
        var y: Int = 0
    }
    var p = Point(a)// Add a breakpoint here and run the program
}

testStruct()

* * * * * * * * * * * * * * *Assembly codeSwiftTest`init(a) in Point #1 in testStruct():
->  0x1000010b0 <+0>:  pushq  %rbp
    0x1000010b1 <+1>:  movq   %rsp, %rbp
    0x1000010b4 <+4>:  xorps  %xmm0, %xmm0
    0x1000010b7 <+7>:  movaps %xmm0, -0x10(%rbp)
    0x1000010bb <+11>: movq   $0x0, -0x10(%rbp)
    0x1000010c3 <+19>: movq   $0x0, -0x8(%rbp)
    0x1000010cb <+27>: xorl   %eax, %eax
    0x1000010cd <+29>: movl   %eax, %ecx
    0x1000010cf <+31>: movq   %rcx, %rax
    0x1000010d2 <+34>: movq   %rcx, %rdx
    0x1000010d5 <+37>: popq   %rbp
    0x1000010d6 <+38>: retq 
Copy the code
func testStruct(a) {
    struct Point {
        var x: Int
        var y: Int
        init(a) {
            x = 0
            y = 0}}var p = Point(a)// Add a breakpoint here and run the program
}

testStruct()

* * * * * * * * * * * * * * *Assembly codeSwiftTest`init(a) in Point #1 in testStruct():
->  0x1000010b0 <+0>:  pushq  %rbp
    0x1000010b1 <+1>:  movq   %rsp, %rbp
    0x1000010b4 <+4>:  xorps  %xmm0, %xmm0
    0x1000010b7 <+7>:  movaps %xmm0, -0x10(%rbp)
    0x1000010bb <+11>: movq   $0x0, -0x10(%rbp)
    0x1000010c3 <+19>: movq   $0x0, -0x8(%rbp)
    0x1000010cb <+27>: xorl   %eax, %eax
    0x1000010cd <+29>: movl   %eax, %ecx
    0x1000010cf <+31>: movq   %rcx, %rax
    0x1000010d2 <+34>: movq   %rcx, %rdx
    0x1000010d5 <+37>: popq   %rbp
    0x1000010d6 <+38>: retq   
Copy the code

Comparing the above two programs, the assembly code underlying the no-parameter initializer function they call is exactly the same, so it is equivalent. Grammar sugar may deceive, but assembly never will.


Structures exist within structures

struct Point {
    var x: Int = 10
    var y: Int = 20
    var origin: Bool = true
}
var p = Point(a)print(MemoryLayout<Point>.size)
print(MemoryLayout<Point>.stride)
print(MemoryLayout<Point>.alignment)
print(Mems.memStr(ofVal: &p)) // Output the data stored in the structure

* * * * * * * * * * * * * * * *The results17
24
8
0x000000000000000a 0x0000000000000014 0x0000000000000001
Program ended with exit code: 0
Copy the code

It can be seen that the structure of Swift is the same as the structure of C language, and the memory of member variables are all close together


class

The definition of a class is similar to that of a structure, but the compiler does not automatically generate initializers for classes that can pass in member valuesIn each member of the classThere areBy default, a no-parameter initializer is created for itOne thing to notevar x: Int?isoptional, so it automatically gets a default valuenil. Compared withStruct.ClassThe statement is almost identical toStructExactly the same, you can also add methods internally. From the table, only the initializer is a little different.


Class initializer

Initialization of a member is done in this initializer. Here is the code that is exactly equivalent at both ends (same as above — assembly).

class Point {
    var x: Int = 10
    var y: Int = 20
}
let p = Point(a)Copy the code
class Point {
    var x: Int
    var y: Int
    init(a) {
        x = 10
        y = 20}}let p = Point(a)Copy the code


Essential differences between structures and classes

Structs are value types (enumerations are also value types) and classes are reference types (pointer types)

class Size {
    var width = 1
    var height = 2
}

struct Point {
    var x = 3
    var y = 4
}

func test(a) {
    var size = Size(a)var point = Point()}Copy the code

In the code abovesizeandpointThe distribution in memory is as follows


Object heap space application process

Take a look at the following scenario

func testClassAndStruct(a) {
    class Size {
        var width = 1
        var height = 2
    }

    struct Point {
        var x = 3
        var y = 4
    }

    var size = Size(a)//----- add a breakpoint here and run to open the assembly interface
    //var point = Point()
}

testClassAndStruct()
Copy the code

To create an instance object of a class in Swift, the process is as follows

  • Class.__allocating_init()
  • libswiftCore.dylib:_swift_allocObject_
  • libswiftCore.dylib:swift_slowAlloc
  • libsystem_malloc.dylib:malloc

The malloc function on Mac and iOS always allocates a multiple of 16 memory size. Class_getInstanceSize tells you how much memory an object of your class actually uses

class Point {
    var x = 11
    var test = true
    var y = 22
}
var p = Point(a)print(class_getInstanceSize(type(of: p)))  / / 40
print(class_getInstanceSize(Point.self))   / / 40
Copy the code


Value types

  • Value type assigned tovar,letOr you can just pass a parameter to a function, or you can just make a copy of everything

It’s like doing a filecopy,pasteOperation produces a brand new copy of the file. Belong to deep copy (deep copy)


The assignment operation of a value type

  • In the Swift standard library, to improve performance,String,Array,Dictionary,SetTo take theCopy On WriteThe technical
    1. For example, a copy operation is performed only when there is a write operation
    2. Swift ensures optimal performance for assignment operations of library value types, so there is no need to avoid assignment in order to ensure optimal freshness

Note that this is for the Swift standard library only. Swift does not use Copy On Write for custom constructs

  • Suggestion: If no modification is required, try to define it aslet
var s1 = "Jack"
var s2 = s1
s2.append("_Rose")
print(s1)//Jack
print(s2)//Jack_Rose

var a1 = [1.2.3]
var a2 = a1
a2.append(4)
a1[0] = 2
print(a1)//[1,3,4]
print(a2)/ / [1, 2, 3, 4]

var d1 = ["max": 10."min":2]
var d2 = d1
d1["other"] = 7
d2["max"] = 12
print(d1)//["other": 7, "max": 10, "min":2]
print(d2)//["max": 12, "min":2]
Copy the code


Reference types

  • Reference assignment tovar,letOr to pass a parameter to a function, make a copy of the memory address

Similar to making a file substitute (shortcut, link) that points to the same file. Belongs to a shallow copy

class Size {
    var width: Int
    var height: Int
    init(width: Int.height: Int) {
        self.width = width
        self.height = height
    }
}

func test(a) {
    var s1 = Size(width: 10, height: 20)
    var s2 = s1

    s2.width = 11
    s2.height = 22
}

test()
Copy the code


An assignment operation of a reference type

class Size {
    var width: Int
    var height: Int
    init(width: Int.height: Int) {
        self.width = width
        self.height = height
    }
}

var s1 = Size(width: 10, height: 20)
s1 = Size(width: 11, height: 12)
Copy the code


Value type, reference type let

To summarize, let means that the contents of the memory space corresponding to the constant it modifies cannot be modified.

  • Since all the members of a value type are in its memory, its internal members cannot be modified when it is modified by a let
  • A reference type has only Pointers in memory, so the value of this pointer cannot be changed. However, the object instance that the pointer points to is not in the memory of the reference type. Therefore, after being modified by let, the value of the heapspace object can still be changed.


Nested types

struct Poker {
    enum Suit: Character {
        case spades = "️", heart = "️", diamonds = "️", clubs = "️"
    }
    enum Rand: Int {
        case two = 2, three, four, five, six, seven, eight, nine, ten
        case jack, queen, king, ace
    }
}
print(Poker.Suit.heart.rawValue)

var suit = Poker.Suit.spades
suit = .diamonds

var rank = Poker.Rand.five
rank = .king
Copy the code


Enumerations, structures, and classes can all define methods

  • Functions defined in enumerations, structures, and classes are generally called methods
class Size {
    var width = 10
    var height = 10
    func show(a) {
        print("width= \(width), height= \(height)")}}let s = Size()
s.show()

struct Point {
    var x = 10
    var y = 10
    func show(a) {
        print("x= \(x), y= \(y)")}}let p = Point()
p.show()

enum PokerFace: Character {
    case spades = "️", heart = "️", diamonds = "️", clubs = "️"
    func show(a) {
        print("face is \(rawValue)")}}let pf = PokerFace.heart
pf.show()
Copy the code
  • Do methods occupy memory objects?
    1. Do not take up
    2. Methods are essentially functions
    3. Methods and functions are placed in the code section