Enumeration (enum)
The member type of the enumeration
As opposed to an enumeration of OC. Enumerations in Swift are much more powerful
Enumeration values in OC can only be ints. Enumerations in Swift can be int,char,String. Values in the same enumeration can also be of different types.
RawValue of enumeration
When we type an enumeration, the members of the enumeration must all be of the same type. We can also associate each enumerated value with a default value.
When set to String and Int, Swift automatically sets the raw value for the enumerator
enum Test : String{
case test1 = "test1"
case test2 = "test2"
}
enum Test1 : String{
case test1
case test2
}
print(Test.test1.rawValue) //test1
print(Test1.test1.rawValue) //test1
enum TestNumber:Int {
case first
case seconde
}
enum TestNumber1:Int {
case first = 0
case seconde = 1
}
print(TestNumber.first.rawValue) //0
print(TestNumber1.first.rawValue) //0
Copy the code
The associated value of an enumeration
Member values of enumerations are sometimes stored in association with values of other types.
enum Time {
case intValue(hour:Int,min:Int,sec:Int)
case stringValue(String)
}
var time = Time.intValue(hour: 10, min: 10, sec: 10)
time = .stringValue("10:20:21")
Copy the code
Memory allocation for enumeration
No enumeration of associated values. The memory used in multiple cases is 1 byte. Use only to store enumeration member values. The raw value of the enumeration, however, is obtained by other means. If there is only one case
enum Test { case number case other } MemoryLayout<Test>.size //1 MemoryLayout<Test>.stride //1 MemoryLayout<Test>. Alignment //1 var T = test. number // Memory distribution //00 T = test. other //01 enum Test1 {case number} MemoryLayout<Test1>.size //0 MemoryLayout<Test1>.stride //1 MemoryLayout<Test1>.alignment //1Copy the code
Enumerations of associated values exist. The number of bytes occupied in memory is the size of the maximum associated value of occupied bytes +1.
The last byte holds the enumerated member value. You can also view it as a serial number. Indicates which case is currently in. The preceding byte holds the associated value
enum Test { case number(Int, Int, Int, Int) case other } MemoryLayout<Test>.size //33 MemoryLayout<Test>.stride //40 MemoryLayout<Test>.alignment //8 var t = Test.number(1, 2, 3, 4)/distributed/memory / / 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 / / 02 / / 03 00 00 00 00 00 00 00 / / 4 00 00 00 00 00 00 00 00 / / //00 00 00 00 00 00 00 t = Test.other //00 00 00 00 00 00 00 00 //00 00 00 00 00 00 00 00 //00 00 00 00 00 00 00 00 //00 00 00 00 00 00 00 00 //01 /00 00 00 00 00 00 00 00 00 00 00 00Copy the code
Structure (struct)
The vast majority of exposed types in SWIFT are structures. Enumerations and classes are a small part
Bool Int Double String Array Dictionary is a structure
Initializer for a structure
The architecture automatically generates the initializer
struct A{
var a1: Int
var a2: Int
}
var a1 = A(a1: 10, a2: 10)
var a2 = A(a2: 10) //Missing argument for parameter 'a1' in call
var a3 = A(a1: 10) //Missing argument for parameter 'a2' in call
var a4 = A() //Missing arguments for parameters 'a1', 'a2' in call
struct C {
var a:Int = 0
var b:Int = 0
var c:Int = 0
func printValue() {
print(a,b,c)
}
}
var c1 = C(a: 10, b: 10, c: 10)
var c2 = C(a: 10)
var c3 = C(b: 10)
var c4 = C(c: 10)
var c5 = C()
c1.printValue() //10 10 10
c2.printValue() //10 0 0
c3.printValue() //0 10 0
c4.printValue() //0 0 10
c5.printValue() //0 0 0
struct C1 {
var a:Int
var b:Int
var c:Int
init() {
self.a = 0;
self.b = 0;
self.c = 0;
}
func printValue() {
print(a,b,c)
}
}
var c1 = C1(a: 10, b: 10, c: 10) //Argument passed to call that takes no arguments
var c2 = C1(a: 10) //Argument passed to call that takes no arguments
var c3 = C1(b: 10) //Argument passed to call that takes no arguments
var c4 = C1(c: 10) //Argument passed to call that takes no arguments
var c5 = C1()
c1.printValue() //10 10 10
c2.printValue() //10 0 0
c3.printValue() //0 10 0
c4.printValue() //0 0 10
c5.printValue() //0 0 0
Copy the code
It can be seen from the contrast between A and C. When we don’t declare an initializer. Initializers are automatically generated based on the situation.
- If a structure declares a member variable with an initial value, multiple initializers are generated.
- If a member variable has no initial value, only an initializer that needs to be assigned to all members is automatically generated
Conclusion: When the structure is initialized, all member variables must have values
Compare C and C1, which are basically the same structure. As you can see, if an initializer is defined, no other initializers are automatically generated.
The memory layout of the structure
struct C {
var a:Int = 0
var b:Int = 0
var c:Int = 0
func printValue() {
print(a,b,c)
}
}
var c1 = C(a: 10, b: 10, c: 10)
print(MemoryLayout.size(ofValue: c1))//24
Copy the code
Struct.C. nit method is called to instantiate the structure.
-> 0x100003848 <+8>: movl $0xa, %eax
0x10000384d <+13>: movl %edi, -0x1c(%rbp)
0x100003850 <+16>: movq %rax, %rdi
0x100003853 <+19>: movq %rsi, -0x28(%rbp)
0x100003857 <+23>: movq %rax, %rsi
0x10000385a <+26>: movq %rax, %rdx
0x10000385d <+29>: callq 0x100003b90 ; struct.C.init(a: Swift.Int, b: Swift.Int, c: Swift.Int) -> struct.C at main.swift:10
Copy the code
Structure C. three Int member variables are defined. Memorylayout. size(ofValue: c1) to obtain the result 24. So the conclusion can be drawn. The memory size of a structure is the sum of all member variables. So how is it distributed in memory.
So here we’re looking at the memory distribution through breakpoints
0x100008038 | 0A 00 00 00 00 00 00 00 0A 00 00 00 00 00 00 00 0A 00 00 00 00 00 00 00
Copy the code
24 consecutive bytes after 0x100008038 are found. Each eight bytes is a hexadecimal value 0000000A, that is, 10 in decimal. Indicates that the memory of the structure is continuously distributed on the stack. Each n bit holds the corresponding member variable value. N = The size of bytes occupied by the member variable type.
Structure assignment
What happens when we assign an existing struct variable to another struct variable and modify a member of one of the structs
struct C {
var a:Int = 0
var b:Int = 0
var c:Int = 0
func printValue() {
print(a,b,c)
}
}
var c1 = C(a: 10, b: 10, c: 10)
var c2 = c1
c1.a = 20
c1.printValue() //20 10 10
c2.printValue() //10 10 10
Copy the code
Conclusion The assignment between structures is explained. It’s a deep copy.
When a structure is assigned a value to another structure, a contiguous segment of memory is reopened and the corresponding value is put in place. When this is done, the two structures are completely independent.
We can look at their memory distribution as shown above
c1--0x100008038 | 14 00 00 00 00 00 00 00 0A 00 00 00 00 00 00 00 0A 00 00 00 00 00 00 00
c2--0x100008050 | 0A 00 00 00 00 00 00 00 0A 00 00 00 00 00 00 00 0A 00 00 00 00 00 00 00
Copy the code
You can see that the memory distribution is exactly 24 bytes different. The structure is continuously distributed on the stack.
Structure copy on write
In Swift,String, Array, Dictionary and other structure types, in order not to waste memory, adopt copy on write operation.
That is, when the type above is assigned, if no write operation is performed. Both variables point to the same block of address. A copy operation is performed only when a write operation is performed.
Class (class)
Class initializer
Classes and structures look very similar. But the rules for class generation initializers are different.
class A {
var a = 0
var b = 0
}
let a = A()
class B { //Class 'B' has no initializers
var a : Int
var b : Int
}
let b = B() //'B' cannot be constructed because it has no accessible initializers
class C {
var a : Int
var b : Int
init() {} //Return from initializer without initializing all stored properties
}
let c = C()
class D {
var a : Int
var b : Int
init() {
self.a = 0
self.b = 0
}
}
let d = D()
class E {
var a : Int
var b : Int
init(a:Int, b:Int) {
self.a = a
self.b = b
}
}
let e = E(a: 10, b: 10)
Copy the code
As can be seen from the example above. If you declare a class, there are several possibilities
- Initial values are added to member variables of the class. An initializer with no arguments is automatically generated.
- Class member variables that have no initializers declare parameterless initializers that need to be assigned in the initializers
- Manually declare initializers with parameters
Class memory distribution
From assembly below, you can see that __allocating_init is called when the class is initialized.
class A {
var a = 10
var b = 10
}
let a = A()
-> 0x100003251 <+17>: movq %rcx, %rdi
0x100003254 <+20>: movq %rsi, -0x18(%rbp)
0x100003258 <+24>: callq 0x1000032a0 ; type metadata accessor for struct.A at <compiler-generated>
0x10000325d <+29>: movq %rax, %r13
0x100003260 <+32>: movq %rdx, -0x20(%rbp)
0x100003264 <+36>: callq 0x1000036e0 ; struct.A.__allocating_init() -> struct.A at main.swift:11
Copy the code
Tracing further down,_allocating_init->_swift_allocObject -> swift_slow_alloc -> malloc
You will see that the malloc method is finally called. Note during initialization of class instance objects. A new section of memory is created in the heap space to hold the contents of the instance object. So let’s see what’s in the heap space
a | 0x10057fc20 28 82 00 00 01 00 00 00
03 00 00 00 02 00 00 00
0A 00 00 00 00 00 00 00
0A 00 00 00 00 00 00 00
Copy the code
By looking at the memory distribution. I found two values of 0A. That’s exactly what a and B are. The first 16 bits. Store the reference count and type information of the object respectively
Class assignment
class A { var a = 10 var b = 10 func printValue() { print(a,b) } } let a = A() let b = a b.a = 20 a.printValue() //20 10 b.printValue() //20 10Copy the code
Unlike structs, class assignments are shallow copies. It’s just a copy of the heap address. Changing the value of one instance object variable causes the value of the other to change
Class and structure
Type:
- Structure: Value type assigned to another parameter. Equal value pass. Will copy one more memory. And the two parts of the memory is completely independent. Deep copy
- Class: Reference type assignments are passed by reference, passing only a shallow copy of the pointer
In memory:
- Struct: N consecutive bytes on the stack. N = the size of the structure, which may exist in the stack or global area (data segment)
- Class: holds pointer variables on the stack. The pointer points to the address of the actual class object in the heap. The class always exists in the heap. But Pointers to it may have stacks or global extents.
Initialization:
-
Struct: Just call the init method
-
Class: _allocating_init -> _swift_allocObject -> swift_slow_alloc -> malloc