Declaration of enumeration

Definition of enumeration
Enum SomeEnumeration {// use case to modify enumeration item}Copy the code

Declare an enumeration in one direction with four enumerations: east, west, South, and north.

enum Direction {
    case east
    case west
    case north
    case south
}

let east = Direction.east
var head: Direction = .west
head = .north
Copy the code

Swift enumerators are themselves complete values when they are created, and these values are of a well-defined Direction type. It’s not given a default integer value like Objective-C. In the Direction example above, east, west, north, and south are not implicitly assigned 0,1,2, and 3.

Enumeration naming and use notes:
  • The first letter of the enumeration must be uppercase, and the first letter of the enumeration value must be lowercase;
  • The enumeration type has a singular name instead of a plural name, so that it can act as the name implies;
  • Once the enumeration type is determined, it is recommended to use dot syntax to set the value;

2. Enumeration features

  • Enumerator types in Swift: string, character, arbitrary integer value, or floating point type.
  • An enumerator in Swift can specify any type of value to store in association with different member values (collections).
  • Enumerations in Swift are a class of types with their own permissions (computed properties, instance methods, extensions, and so on).

Three. Enumeration value correlation

1. The types of enumerated values

Enumerations in Swift are more flexible and do not have to provide a value for each enumerator. If an enumeration member is given a value (called a primitive value), the value can be of type: string, character, arbitrary integer value, or floating point type.

2. The original value

The Swift enumeration type provides an implementation called RawValues, which provides a default value for an enumeration item that is determined at compile time.

  • Get the original value
let raw = Direction.west.rawValue
Copy the code
  • Generate enumeration items from raw values
let east1 = Direction.init(rawValue: "east")
print(type(of: east1))     
// Optional<Direction>
Copy the code

Enumerations obtained from raw values are of optional type, so you need to use an if let to determine.

if let east = Direction.init(rawValue: "east") {     
    print(type(of: east))     
}
// Direction
Copy the code
3. Implicit and explicit raw values

No enumerated value type is specified

Enum Shape {case Circle case square case oval case trilateral} // Cannot give a value to an enumerated member of an unspecified type (case North = "north"❌) error: Enum case cannot have a raw value if the Enum does not have a raw type // Unspecified enumerator cannot use the rawValue attribute (direction.rawValue❌) error: Value of type 'Direction' has no member 'rawValue'Copy the code

Implicit raw value

enum Shape1: String {
    case circle  
    case square
    case oval
    case trilateral
}
Copy the code

Enumerations with implicit raw values use system-assigned values:

  • If it is a Sting type, the enumeration value is the enumeration itemcase circleIs equivalent tocase circle = "circle"
  • If it is an Int, the first enumeration defaults to 0 and the others step by step +1
  • For floating-point types such as CGFloat, the first enumerated value defaults to 0.0 and the others step by step +1

Explicit raw value

Enum Shape2: String {case circle = "circle" case square = "square" case oval = "ellipse" case Trilateral = "triangle"}Copy the code

Implicit + explicit raw value

Enum Shape4: Int {case circle = 1 case square = // Default is 2 case oval // default is 3 case trilateral // default is 4} enum Shape4: Int {case circle // Default is 0 case square = 2 case oval // default is 3 case trilateral // default is 4}Copy the code
2. Listen for enumeration values
var direction = Direction.east { willSet { if newValue ! = direction {print(" print ")}} didSet {if oldValue! = direction {print(" print ")}}Copy the code

The attribute observer is used here. The enumeration in Swift is more like an object, so it’s easy to use the attribute observer to listen for enumeration values.

3. Associated Values

In Swift, you can also define an enumeration type that has an additional information for each enumeration item to extend the information representation of that enumeration item, which is also called an associated value.

enum Trade {
    case buy(count: Int)
    case sell(count: Int)
}
let trade = Trade.buy(count: 10)
Copy the code

It is important to learn how to use associative values. The details of their use will be covered in section 9 below

4. Correlation value equality judgment

In general enumerations are easy to make equality judgments. Once the associated values are added to the enumeration, Swift cannot compare properly and needs to implement the == operator on the enumeration itself.

Enum Trade {case buy(count: Int) case sell(count: Int)} // Only enumeration values and associated values are equal. func == (before: Trade, after: Trade) -> Bool { switch (before, after) { case let (.buy(count1), .buy(count2)) where count1 == count2: return true case let (.sell(count1), .sell(count2)) where count1 == count2: return true default: return false } } let trade1 = Trade.buy(count: 10) let trade2 = Trade.sell(count: 10) if trade1 == trade2 {print(" same ")} else {print(" same ")}Copy the code
5. Enumeration sort/compare size with associated values
enum SortEnum: Comparable {
    
    case a(Int)
    case b(String)
    indirect case c(SortEnum)
    
    var ordering: Int {
        switch self {
        case .a(_):
            return 0
        case .b(_):
            return 1
        case .c(_):
            return 2
        }
    }
    
    static func < (lhs: SortEnum, rhs: SortEnum) -> Bool {
        lhs.ordering < rhs.ordering
    }
    static func > (lhs: SortEnum, rhs: SortEnum) -> Bool {
        lhs.ordering > rhs.ordering
    }
}

let a = SortEnum.a(0)
let b = SortEnum.b("b")
let c = SortEnum.c(a)
let sortArr: [SortEnum] = [b, c, a]

print(sortArr.sorted())
Copy the code

Use the Comparable protocol to compare enumerations.

Enumeration and Switch

Case. East: print(" east ") case. North,.south,.west: print(" east ")}Copy the code

5. Traversal of enumeration

enum Shape5: CaseIterable { case circle case square case oval case trilateral } for item in Shape5.allCases { print(item) } let count  = Shape5.allCases.countCopy the code

Swift enumerations that comply with the CaseIterable protocol are traversable, fetching all enumerators through allCases.

Nesting of enumerations

If all the interface addresses in app are put together, it is not convenient to name or find them, so we can use enumeration nesting to design. It can be scattered into multiple files for easy maintenance and management.

// Total Interface enum Interface {} extension Interface {// System related Interface enum System {case sendMessage case uploadImage}} extension Interface {// User-related Interface enum User {case name case icon case phone}} interface-.user.loginCopy the code

Enumerations are a good way to manage constants in your system.

Enumerative properties and methods

1. Calculate attributes
Enum AppleDeivce {case iPad, iPhone // Cannot use storage attribute // var deviceName: String? ❌ // error: Enums must not contain stored properties var yeaer: Int {switch self {case. iPad: return 2010 case .iPhone: return 2007 } } } let _ = AppleDeivce.iPhone.yeaerCopy the code

You cannot use storage properties in enumerations, but you can use computed properties, the contents of which are derived from an enumeration value or an enumeration association value.

2. Instance method
enum AppleDeivce {
    case iPad, iPhone, iWatch, other
    
     func introduced() -> String {
        switch self {
        case .iPad:
            return "iPad"
        case .iPhone:
            return "iPhone"
        case .iWatch:
            return "iWatch"
        default:
            return "other"
        }
    }
}
let _ = AppleDeivce.iPhone.introduced()
Copy the code

Here, enumeration can be considered as a class, introduced is a member method and AppleDeivce. IPhone is an instance of AppleDeivce and cases are its attributes. The Switch self introduced was actually going through all the scenarios of the anonymous attribute, such as iPad and iPhone, and then returning different values according to different scenarios.

3. Static methods of enumeration
enum AppleDeivce {
    case iPad, iPhone
    
    static func fromSlang(slang: String) -> AppleDeivce? {
        if slang == "iPhone" {
            return .iPhone
        }
        return nil
    }
}
let _ = AppleDeivce.fromSlang(slang: "iPhone")
Copy the code

Custom constructors that can do enumerations.

Enumerations and protocols

Print protocol of the system

public protocol CustomStringConvertible {
    var description: String { get }
}
Copy the code

Make the enumeration adhere to this protocol

Enum AppleDeivce: CustomStringConvertible {case iPad, iPhone String {switch self {case. IPhone: return return "iPad" } } } let _ = AppleDeivce.iPhone.descriptionCopy the code

Enumeration and extension

Enumerations can be extended. You can separate cases from Method /protocol in enumerations so that readers can quickly digest the contents of enumerations.

enum AppleDeivce { case iPad, iPhone } extension AppleDeivce: CustomStringConvertible { var description: String {switch self {case. IPhone: return return "iPad" } } } extension AppleDeivce { static func fromSlang(slang: String) -> AppleDeivce? { if slang == "iPhone" { return .iPhone } return nil } } extension AppleDeivce { func introduced() -> String { switch self { case .iPad: return "iPad" case .iPhone: return "iPhone" } } } extension AppleDeivce { var yeaer: Int { switch self { case .iPad: return 2010 case .iPhone: return 2007 } } }Copy the code

Enumerations and generics

Design a network class error message processing function.

  • Start by declaring an error message structure containing two property codes and the error message
struct ErrorMessage {
    var code : Int
    var message : String
}
Copy the code
  • Declares an enumeration of network errors

The enumeration takes a generic to accept associated values.

enum NetworkError<T> {
    case codeError(T)
    case wrongReturn
    case networkNull
    case tokenOverdue
}
Copy the code
  • Suppose there is one such enumeration in a network class that is returned through a closure
let errorMessage = ErrorMessage.init(code: 404, message: "not found")
let codeError = NetworkError.codeError(errorMessage)
Copy the code
  • Call network API, network error handling
switch codeError {
case .codeError(let message):
      print(message.code)
      print(message.message)
default:
       break
}
Copy the code

Enumerations and structures

You often use UserDefaults in projects to store simple user information. But the maintenance of keys is not very convenient. And you don’t remember. Enumeration + structures are a good way to solve this problem.

  • The statement agreement
public protocol UserDefaultsSettable {
    associatedtype defaultKeys: RawRepresentable
}

extension UserDefaultsSettable where defaultKeys.RawValue == String {
    static public func set(value: Any, forKey key: defaultKeys) {
        let aKey = key.rawValue
        UserDefaults.standard.set(value, forKey: aKey)
    }
    
    static public func getString(forKey key: defaultKeys) -> String? {
        let aKey = key.rawValue
        let value = UserDefaults.standard.string(forKey: aKey)
        return value
    }
}
Copy the code
  • Add an extension to UserDefaults
public extension UserDefaults { struct Version : UserDefaultsSettable { public enum defaultKeys: String { case version case build } } struct LocationInfo: UserDefaultsSettable { public enum defaultKeys: String {case latitude case longitude}}} String {case longitude}} UserDefaults.Version.set(value: "version", forKey: .version) let version = UserDefaults.Version.getString(forKey: .version)Copy the code

Is the storage module of APP designed in this way more hierarchical and convenient to use?

11. Recursive enumeration

Recursive enumerations are enumerations that have another enumeration associated with a value as an enumerator. The indirection layer must be inserted when the compiler operates on recursive enumerations. You can use the indirect keyword before declaring an enumerator to make it clear that it is recursive. You can also declare that all enumerators are recursive before the entire enumeration.

Find Arithmetic {indirect case add(Arithmetic, indirect case add, indirect case add, indirect case add, indirect case add(Arithmetic, indirect case add, indirect case add) We have no problem finding a pair of expressions in indirect case multiply(find Arithmetic, How can I turn a question into an indirect case? Function func evaluate() -> Double {switch self {case.number (let value): return Double(value) case .add(let item1,let item2): return item1.evaluate() + item2.evaluate() case .subtract(let item1,let item2): return item1.evaluate() - item2.evaluate() case .multiply(let item1,let item2): return item1.evaluate() * item2.evaluate() case .divide(let item1,let item2): Evaluate () == 0 {return Double(int.min)} return item1. Evaluate ()/item2. Evaluate ()}} let two = Arithmetic.number(2) let four = Arithmetic.number(4) let five = Arithmetic.number(5) let sum = Arithmetic.add(five, four) let product = Arithmetic.multiply(sum, Evaluate ()) print(sum. Evaluate ()) print(product. Evaluate ()Copy the code