Enum Original value

1.1 Basic Usage

Swift uses the enum keyword to declare an enumeration:

enum SSLEnum {
    case test_one
    case test_two
    case test_three
}
Copy the code

We know that C and OC accept integers by default, which means that in the following example: A, B, and C default to 0, 1, and 2 respectively

typedef NS_ENUM(NSInteger, SSLEnum) {
    A,
    B,
    C,
};
Copy the code

Enumerations in Swift are more flexible and do not need to provide a value for every member of the enumeration. If you supply a value for an enumeration member (called a primitive value), the value can be a string, a character, an arbitrary integer value, or a floating-point type.

enum Color: String { case red = "Red" case amber = "Amber" case green = "Green" } enum SSLEnum: Double {case a = 10.0 case b = 20.0 case c = 30.0 case d = 40.0}Copy the code

Implicit RawValue allocation is built on Swift’s type inference mechanism.

enum DayOfWeek: String { case mon, tue, wed, thu, fri = "Hello World", sat, Sun} print(dayofweek.rawValue) print(dayofweek.fri.rawValue) print(dayofweek.rawValue) Print (dayofweek.rawValue) Mon Hello World satCopy the code

We can see that the enumeration values of mon and STA are the same as the original values. Let’s see how this is done.

1.2 Sil analysis value process

Add the following code:

enum DayOfWeek: String {
    case mon, tue, wed, thu, fri = "Hello World", sat, sun
}

var x = DayOfWeek.mon.rawValue
Copy the code

Swiftc-ema-sil main.swift >./main.sil && open main.sil generates sil files:

Enum DayOfWeek: String {case mon, tue, wed, thu, FRI, SAT, sun? Typealias rawValue = String var rawValue: String {get} // get function}Copy the code

To get a rawValue, call the get method in the sil file.

If it is mon, then bb1 is called, and the string constant is “mon”. Where is the string constant?

The storage location is as follows:

1.3 Enumeration values and raw values

Enumeration values and primitive values cannot be assigned to each other:

Second, the correlation value

2.1 Basic Usage

Sometimes we want to express something more complex with enumerated values, such as shapes:

Enum Shape {case circle(radios: Double) // Rectangle (width: Double, height: // radios: 1 var circle = shape. circle(radios: 10)Copy the code

2.2 Pattern Matching

Switch pattern matching

enum Weak: String {
    case MONDAY
    case TUEDAY
    case WEDDAY
    case THUDAY
    case FRIDAY
    case SATDAY
    case SUNDAY
}

let currentWeak: Weak = Weak.MONDAY

switch currentWeak {
    case .MONDAY: print(Weak.MONDAY.rawValue)
    case .TUEDAY: print(Weak.MONDAY.rawValue)
    case .WEDDAY: print(Weak.WEDDAY.rawValue)
    case .THUDAY: print(Weak.THUDAY.rawValue)
    case .FRIDAY: print(Weak.FRIDAY.rawValue)
    case .SATDAY: print(Weak.SATDAY.rawValue)
    case .SUNDAY: print(Weak.SUNDAY.rawValue)
}
Copy the code

If you do not want to match all cases, use the default keyword:

enum Weak: String {
    case MONDAY
    case TUEDAY
    case WEDDAY
    case THUDAY
    case FRIDAY
    case SATDAY
    case SUNDAY
}

let currentWeak: Weak = Weak.MONDAY

switch currentWeak {
    case .SATDAY, .SUNDAY: print("Happy Day")
    default : print("SAD Day")
}
Copy the code

If we want to match the correlation value:

enum Shape{ case circle(radious: Double) case rectangle(width: Int, height: Int) } let shape = Shape.circle(radious: Rectangle {case let. circle(radious): print(" circle radious:\(radious)") case let. rectangle(width, height): print("rectangle width:\(width),height\(height)") }Copy the code

You can also write:

enum Shape{ case circle(radious: Double) case rectangle(width: Int, height: Int) } var shape = Shape.circle(radious: 10.0) Switch Shape {case. Circle (let radious): print("Circle radious:\(radious)") case .rectangle(let width, let height): print("rectangle width:\(width),height\(height)") }Copy the code

Enumerate size

3.1 No – content enums

So let’s talk about the size of the memory that enumerations take up, and there are several different kinds of cases. The first one is the no-payload enums, which are enumerations that have No associated values.

enum Week {
    case MONDAY
    case TUEDAY
    case WEDDAY
    case THUDAY
    case FRIDAY
    case SATDAY
    case SUNDAY
}
Copy the code

As you can see, enumerations of this type are similar to enumerations in C. The default type is Int. And how much memory does it take up? Here we can measure the current enumeration directly using MemoryLayout

  • You can see that both the size and stribe that we tested here are 1
  • Enumeration layouts in Swift have always tried to store enUms with minimal space, with 1 byte representing 256 cases
  • That is, a default enumeration type with no associated value and case less than 256. The current enumeration type is all 1 byte in sizeUInt8

According to the above print, we can see intuitively that the contents of the three variables a, b and c are 00,01,02 respectively, which is consistent with the layout understanding we said above.

3.2 Single – content enums

Let’s look at the memory layout of single-payload enums, which literally means an enum with only one payload, as in the following example

enum SSLEnum { case test_one(Bool) case test_two case test_three case test_four } enum SSLEnum2 { case test_one(Int) case test_two case test_three case test_four } print(MemoryLayout<SSLEnum>.size) print(MemoryLayout<SSLEnum2>.size) The output is as follows: 1 9Copy the code
  • Why is there a single load, but the current occupancy is not the same size!
  • Pay attention to,SwiftEnum inSingle-payload enumsThe extra space in the load type is used to record case values that are not loaded.
  • forBoolType versus load,BoolThe type is 1 byte, but it only takes 1 bit to store, forUInt8For enumerations of types, there is still 7 bits of space to represent 128 cases, so 1 byte is fine.
  • forIntType of load, in fact, the system is no way to calculate the current load to use the number of bits, which means the currentIntType loads have no extra free space, so we need to allocate extra memory to store our case values, which are 8 + 1 = 9 bytes.

3.3 Mutil – content enums

The third case is mutil-payload enums, where there are multiple loads.

Look at the following example:

enum SSLEnum { case test_one(Bool) case test_two(Bool) case test_three case test_four } enum SSLEnum2 { case test_one(Int) case test_two(Int) case test_three(Int) case test_four(Int) } enum SSLEnum3 { case test_one(Bool) case test_two(Int) case test_three case test_four } enum SSLEnum4 { case test_one(Int, Int, Int) case test_two case test_three case test_four } print(MemoryLayout<SSLEnum>.size) print(MemoryLayout<SSLEnum2>.size) Print (MemoryLayout<SSLEnum3>. Size) print(MemoryLayout<SSLEnum4>. Size) The following output is displayed: 1 9 9 25Copy the code
  • We can see from the output that when we have multiple loaded enumerations, the size of the enumeration depends on the size of the current maximum associated value
  • If the number of bits required for the maximum correlation value is less than 8, and there is still room to represent all cases, the size of the enumeration is1
  • If the maximum associated value requires more than 8 bits, the size of the enumeration =Maximum correlation value + 1

3.4 Special Cases

And then finally there’s a special case that we need to understand, so let’s look at the following case

enum SSLEnum {
    case test_one
}
Copy the code

There is only one case for the current SSLEnum and we do not need anything to distinguish the current case, so when we print the current SSLEnum size you will find that it is 0.

Iv. Indirect keywords

Let’s look at the following error code:

Because enumerations are value types, the compile-time size is determined, and the associated value is an enumeration type, so there is no way to determine.

It is not a mistake to prefix the enumeration with an indirect, which assigns a BinaryTree to the heap space

Print the size of BinaryTree:

Print (MemoryLayout<BinaryTree<Int>>. SizeCopy the code

You can see that the sample size is 8 and is a reference type.

In addition to the enumeration, I can place an indirect before a case

enum BinaryTree<T> {
    case empty(Int)
    indirect case node(left: BinaryTree, value: T, right: BinaryTree)
} 
Copy the code

At this point, not the entire enum is a reference type, only node is a reference type.

Five, the Optional

5.1 optional value

5.1.1 Understanding optional Values

We’ve already touched on optional values in our code. For example, we defined them in code like this:

class SSLTeacher {
    var age: Int?
}
Copy the code

The current age is called the optional value, and of course the optional value is written the same as the following:

var age: Int?
var age: Optional<Int>
Copy the code

What is the nature of that for Optional? Let’s jump straight to the source and open the Optional. Swift file:

@frozen
public enum Optional<Wrapped>: ExpressibleByNilLiteral {
  case none
  case some(Wrapped)
}
Copy the code

Since Optional is essentially enumeration, we can make our own Optional modeled after the implementation of the system

enum MyOptional<Value> {
    case some(Value)
    case none
}
Copy the code

For example, given any natural number, return if the current natural number is even, nil otherwise, how should we express this case:

func getOddValue(_ value: Int) -> MyOptional<Int> {
    if value & 2 == 0 {
        return .some(value)
    } else {
        return .none
    }
} 
Copy the code

Given an array, we want to delete all the even numbers in the array:

At that point the compiler will check our current value and see that it doesn’t match the type the system compiler expects, so we can use MyOptional to limit syntax security.

Fetch the corresponding value through enum pattern matching:

var array = [1, 2, 3, 4, 5, 6]
for element in array {
    let value = getOddValue(element)
    switch value {
    case .some(let value):
        array.remove(at: array.firstIndex(of: value)!)
    default:
        print("value not exist")
    }
} 
Copy the code

If we change the above return value, we will use the system Optional

func getOddValue(_ value: Int) -> Int? {
    if value & 2 == 0 {
        return .some(value)
    } else {
        return .none
    }
}
Copy the code

In this way, we are taking advantage of the current compiler’s type checking to achieve syntactic writing security.

5.1.2 the if the let

Of course, if every optional value is obtained by pattern matching, it would be tedious to write the code. We can also use the if let mode to bind the optional value:

if let value = value {
    array.remove(at: array.firstIndex(of: value)!)
}
Copy the code

5.1.3 gurad let

In addition to using if lets to handle optional values, we can also use Gurad lets to simplify our code,

  • Gurad let is the opposite of if let
  • The Gurad let daemon must have some value. If not, return directly
  • Usually judge if there is a value, will do a specific logical implementation, usually more code

Let’s look at a specific case:

let name: String? = "ssl" let age: Int? Guard let newName = name else {print(" name is empty ") return} Guard let newAge = age else {print(" age is empty ") return} // Print (newName + String(newAge))Copy the code

5.1.3 optional link chain

We know that in OC nothing happens when we send a message to a nil object, and in Swift we have no way of sending a message directly to a nil object, but we can achieve a similar effect with optional chains.

Let’s start with the following code

let str: String? = "abc" let upperStr = str? .upperstr () print(upperStr) // output: Optional<"ABC"> var str1: String? let upperStr1 = str1? .upperstr1 print(upperStr1) // outputs: nilCopy the code

So what does this code say

let str: String? = "ssl" let upperStr = str? .uppercased().lowerstr () print(upperStr) // output: Optional(" SSL ")Copy the code

The same optional chain applies to subscripts and function calls

var closure: ((Int) -> ())? closure? (1) // Closure for nil does not execute let dict: NSDictionary? = ["one": 1, "two": 2] print(dict? ["one"]) // Output: Optional(1) print(dict? ["three"]) // Output: nilCopy the code

5.2?? Operator (null merge operator)

( a ?? B) The optional type a is nullified and unpacked if a contains a value, otherwise a default value b is returned

  • The expression a must be of type Optional
  • The type of the default value B must be the same as the type of the value a stores

Look at the following example:

var age: Int? var x = age ?? Print (x)Copy the code

5.3 Operator overloading

In the source we can see that in addition to the overload?? Operator Optional also overloads ==,? = and so on. In practice, we can simplify our expressions by overloading the operators.

For example, if we define a two-dimensional vector in development and we want to perform basic operations on two vectors, we can override the operators to do so

extension Vector { static func + (fistVector: Vector, secondVector: Vector) -> Vector { return Vector(x: fistVector.x + secondVector.x, y: fistVector.y + secondVector.y) } static prefix func - (vector: Vector) -> Vector { return Vector(x: -vector.x, y: -vector.y) } static func - (fistVector: Vector, secondVector: Vector) -> Vector { return fistVector + -secondVector } } var v1 = Vector(x: 10, y: 20) var v2 = Vector(x: 20, y: 30) var v3 = v1 + v2 print(v3) var v4 = -v3 print(y: 50) var v3 = -v3 print(y: 50)Copy the code

We can also customize operators, as shown in the following example:

infix operator --- : AdditionPrecedence precedencegroup SSLPrecedence { lowerThan: AdditionPrecedence associativity: left } struct Vector { let x: Int let y: Int } extension Vector { static func --- (fistVector: Vector, secondVector: Vector) -> Vector { return Vector(x: fistVector.x * secondVector.x, y: fistVector.y * secondVector.y) } } var v1 = Vector(x: 10, y: 20) var v2 = Vector(x: 20, y: Print (x: 200, y: 600) print(x: 200, y: 600)Copy the code

For custom operators, check out the official documentation.

5.4 Implicit Resolution of Optional types

Implicit resolution of optional types is one type of optional type and is used in the same way as non-optional types. The only difference is that implicitly resolving the optional type tells the Swift compiler that the value will not be nil when accessed at runtime.

Take a look at the following sample code:

Age1 implicitly resolves optional types, so we don’t need to unpack it anymore, the compiler already does that for us.

If you run the project, you will find that there is no problem at compile time, but you will still get an error if there is no value: