class

  • Class
Class PDTeacher {var age:Int func teach() {print("teach")} init(_ age: Int) {self. Age = age}} class PDTeacher2 {var age:Int? ; func teach() { print("teach") } init(_ age: Int) { self.age = age } } var t1 = PDTeacher2.init(12)Copy the code
  • In class, if the attribute is not assigned and is not optional, the compiler will report an error and you need to implement it yourselfinitmethods

Why do classes refer to types?

Define a class, illustrated by an example

   class CJLTeacher1 {
    var age: Int = 18
    var age2: Int = 20
}
var t1 = CJLTeacher1()
Copy the code

Class initialized object T1, stored in the global area

  • Print T1, T:po t1As can be seen from the figure,t1The memory space containsaddress.tIs stored invalue

  • Get the address of the T1 variable and check its memory
  • Get t1 pointer address:po withUnsafePointer(to: &t1){print($0)}
  • Check the memory status of t1 global region address:x/8g 0x0000000100008218
  • Check the heap area address memory stored in t1 address:x/8g 0x00000001040088f0

Reference Type Characteristics

  • 1, the address stored in isThe heap area address
  • 2,The heap area addressIs stored invalue

Question 1: t1 is assigned to T2. If T2 is changed, will T1 be changed?

  • throughlldbDebug informed, modifiedt2, which may lead tot1Change, mainly becauset2,t1The addresses are all stored inSame heap address, the same heap area address is changed, so changing T2 will cause t1 to be changed together, i.eShallow copy

Question 2: If the structure contains class objects, does t change if you modify the instance object properties in T1?

The code is shown below

class CJLTeacher1 { var age: Int = 18 var age2: Int = 20 } struct CJLTeacher { var age: Int = 18 var age2: Int = 20 var teacher: CJLTeacher1 = CJLTeacher1()} var t = CJLTeacher() var t1 = t t1.teacher.age = 30 // Print teacher t1.teacher.age = 30 t.teacher.age = 30Copy the code

As can be seen from the printed results, if the instance object properties in T1 are modified, the instance object properties in T will change. Although in the struct it is passed by value, in the case of teacher it is still passed by address 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 memory for T:x/8g 0x0000000100008238
  • Print the memory condition of teacher address in T:x/8g 0x000000010070e4a0

Pay attention toWhen writing code, you should try toAvoid value types containing reference types

Looking at the current SIL file, although CJLTeacher1 is placed in the value type, teacher is managed by reference count during passing, whether passing or assigningWe can verify our claim by printing the teacher’s reference count, where the teacher’s reference count is 3

Mainly because:

  • Retain once in main

  • Retain once in the teacher.getter method

  • Retain once in the setter method of teacher

mutating

A stack is defined by a structure. The main methods are push and POP, and we need to dynamically modify the array in the stack

  • If you write it this way, you will get an error becauseThe value type itself does not allow you to modify attributesthe

  • Change the push method to the following and view the push function in the SIL file
struct CJLStack {
    var items: [Int] = []
    func push(_ item: Int){
        print(item)
    }
}
Copy the code

As you can see, the push function has a default argument, self, in addition to item,Self is a let typeSaid,No modifications allowed

  • Try 1: If you modify the push function to look like this, can you add it?
struct CJLStack {
    var items: [Int] = []
    func push(_ item: Int){
        var s = self
        s.items.append(item)
    }
}
Copy the code

The print result is as followsWe can deduce that the above code does not add the item because s is another structure object, which is equivalent to a copy of the value. In this case, we call push to add the item to the s array

  • Add mutating to push according to the error in the previous article, and find that you can add to the array
struct CJLStack {
    var items: [Int] = []
    mutating func push(_ item: Int){
        items.append(item)
    }
}
Copy the code

Look at theSILFile, find the push function, and discover that unlike before, push adds mutating (only for value types), which is essentially toThe inout keyword is added to the value type functionIn the process of passing the value, what is passed isReferences (that is, addresses)

Inout keywords

  • In general, in the function declaration, the default parameterIt's immutableIf you want to modify directly, you need to add the parameterinoutThe keyword
  • withoutinoutKeyword, assign value to parameter, compile error

  • addinoutKeyword to assign values to parameters

conclusion

  • 1. Functions in a structure that want to modify attributes need to be preceded by mutating; classes do not

  • 2. Mutating essence is self with an inout modifier

  • 3. Inout is equivalent to taking an address. It can be understood as address passing, that is, reference

  • 4, mutating and inout modify parameters

conclusion

View the memory model of struct & class through the LLDB above, and summarize as follows:

  • Value type is equivalent to a local Excel. When we send you an Excel through QQ, it is equivalent to a value type. What have you modified that we do not know

  • The reference type, which is equivalent to an online table, when we co-edit a previous table with you, is equivalent to a reference type, and both sides see the changes

  • If you want to modify a function property in a structure, you need to add the mutating keyword before the function. Essentially, you add the inout keyword to the default parameter self, changing self from a let constant to a var variable