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 yourself
init
methods
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 t1
As can be seen from the figure,t1
The memory space containsaddress
.t
Is 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 is
The heap area address
- 2,
The heap area address
Is stored invalue
Question 1: t1 is assigned to T2. If T2 is changed, will T1 be changed?
- through
lldb
Debug informed, modifiedt2
, which may lead tot1
Change, mainly becauset2
,t1
The 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 because
The value type itself does not allow you to modify attributes
the
- 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 type
Said,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 theSIL
File, 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 function
In the process of passing the value, what is passed isReferences (that is, addresses)
Inout keywords
- In general, in the function declaration, the default parameter
It's immutable
If you want to modify directly, you need to add the parameterinout
The keyword - without
inout
Keyword, assign value to parameter, compile error
- add
inout
Keyword 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