Những đặc điểm của enum trong Swift



  • Enum là gì?

    An enumeration defines a common type for a group of related values and enables you to work with those values in a type-safe way within your code.

    => Enum định nghĩa 1 nhóm các giá trị có liên quan đến nhau và cho phép bạn làm việc với những giá trị đó 1 cách an toàn trong code của bạn

    Nhắc lại 1 chút về định nghĩa cho vui thôi :D bài viết này mình sẽ tập trung nói về cú pháp, cách sử dụng và cùng sử dụng nó trong các bài toán thực tế.

    Enum cơ bản

    Nếu bạn làm việc với scroll direction, bài toán đặt ra là bạn cần phải xác định được chiều scroll. Chắc hẳn khi các bạn tập tọe code thì điều đầu tiên các bạn nghĩ đến là là tạo 1 biến thế này đúng không? (trước mình toàn thế thôi á :D)

    var isScrollUp = true
    

    Nhưng thế này là không ổn nhé. Vì không may scrollView của bạn scroll được cả 4 hướng thì sao? (khóc-ing)

    Trong tình huống đó thì enum sẽ là sự lựa chọn hoàn hảo, cùng xem ví dụ nhé:

    enum ScrollDirection {
        case left
        case right
        case up
        case down
    }
    

    Và sau đó bạn hoàn toàn có thể control việc scroll nhé: (cười)

    let scrollDirection = ScrollDirection.down
    
    switch scrollDirection {
    case .down:
        print("scroll down")
    default:
        break
    }
    
    if case .down == scrollDirection {
        print("scroll down")
    }
    
    if scrollDirection == .down {
        print("scroll down")
    }
    

    Enum values

    Trong nhiều trường hợp bạn cần set giá trị cho từng case của enum để tiện sử dụng. Hiểu được điều này Swift cung cấp nhiều cách để bạn có thể set giá trị cho nó

    // Mapping to Integer
    enum Movement: Int {
        case left = 0
        case right = 1
        case top = 2
        case bottom = 3
    }
    
    // You can also map to strings
    enum House: String {
        case baratheon = "Ours is the Fury"
        case greyjoy = "We Do Not Sow"
        case martell = "Unbowed, Unbent, Unbroken"
        case stark = "Winter is Coming"
        case tully = "Family, Duty, Honor"
        case tyrell = "Growing Strong"
    }
    
    // Or to floating point (also note the fancy unicode in enum cases)
    enum Constants: Double {
        case π = 3.14159
        case e = 2.71828
        case φ = 1.61803398874
        case λ = 1.30357
    }
    
    

    Trong trường hợp giá trị của case trong Enum là Int hoặc String. Bạn có thể bỏ qua giá trị của nó mà Swift vẫn tự hiểu và chạy đúng:

    // Mercury = 1, Venus = 2, ... Neptune = 8
    enum Planet: Int {
        case Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
    }
    
    // North = "North", ... West = "West"
    enum CompassPoint: String {
        case North, South, East, West
    }
    

    Nesting Enums

    Hãy tưởng tượng một nhân vật trong một trò chơi. Mỗi nhân vật có thể có một vũ khí, tất cả các nhân vật đều có quyền truy cập cùng một bộ vũ khí. Tất cả các nhân vật khác trong trò chơi không có quyền truy cập vào những vũ khí (họ đang có nhiệm vụ khác...)

    enum Character {
      enum Weapon {
        case Bow
        case Sword
        case Lance
        case Dagger
      }
      enum Helmet {
        case Wooden
        case Iron
        case Diamond
      }
      case Thief
      case Warrior
      case Knight
    }
    

    Bây giờ bạn có một hệ thống có thứ bậc để mô tả các mục khác nhau mà nhân vật của bạn có quyền truy cập rồi:

    let character = Character.Thief
    let weapon = Character.Weapon.Bow
    let helmet = Character.Helmet.Iron
    

    Containing Enums

    Để dễ hiểu: Containing Enums có nghĩa là bạn có thể để enum nằm trong struct hay class khác.
    Vẫn với ví dụ về vũ khí bên trên nhé:

    struct Character {
       enum CharacterType {
        case Thief
        case Warrior
        case Knight
      }
      enum Weapon {
        case Bow
        case Sword
        case Lance
        case Dagger
      }
      let type: CharacterType
      let weapon: Weapon
    }
    
    let warrior = Character(type: .Warrior, weapon: .Sword)
    

    Nó vẫn giúp giữ thông tin liên hệ gữa các đối tuơng đúng không? :)

    Associated values

    Đây là 1 cách tuyệt vời để bạn có thể gắn thêm thông tin vào 1 enum case.
    Ví dụ bạn cần xây định nghĩa barcode của sản phẩm. Có 2 loaị barcode là UPC gồm 4 chữ số, và QRCode là 1 đoạn String. Bạn có thể định nghĩa nó như sau:

    enum Barcode {
        case upc(Int, Int, Int, Int)
        case qrCode(String)
    }
    

    Khi đó bạn có thể tạo 1 biến barcode như sau:

    var productBarcodeUPC = Barcode.upc(8, 85909, 51226, 3)
    var productBarcodeQr = Barcode.qrCode("ABCDEFGHIJKLMNOP")
    

    Để so sánh 1 enum có Associated values bạn có thể làm như sau:

    switch productBarcode {
    case .upc(let numberSystem, let manufacturer, let product, let check):
        print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).")
    case .qrCode(let productCode):
        print("QR code: \(productCode).")
    }
    

    bạn có thể bỏ "let" (hoặc var) đi và dùng như sau:

    switch productBarcode {
    case let .upc(numberSystem, manufacturer, product, check):
        print("UPC : \(numberSystem), \(manufacturer), \(product), \(check).")
    case let .qrCode(productCode):
        print("QR code: \(productCode).")
    }
    

    Methods

    Bạn có thể thêm các hàm cho enum như sau:

    enum Device: String {
        case iphone
        case ipad
        case tv
        case watch
    
        func getOS() -> String {
            switch self {
            case .ipad, .iphone:
                return "iOS"
            case .watch:
                return "WatchOS"
            case .tv:
                return "tvOS"
            }
        }
    }
    

    Properties

    Bạn không thể thêm Stored Properties cho enum. Nhưng bạn vẫn có thể tạo computed properties như sau:

    enum Device: String {
        case iphone
        case ipad
        case tv
        case watch
    
        var description: String {
            switch self {
            case .ipad, .iphone:
                return "iOS"
            case .watch:
                return "WatchOS"
            case .tv:
                return "tvOS"
            }
        }
    }
    

    Static Methods

    Bạn cũng có thể thêm 1 static methods cho enum như sau:

    enum Device: String {
        case iphone
        case ipad
        case tv
        case watch
    
        static func biggestDevice() -> Device {
            return Device.tv
        }
    }
    print(Device.biggestDevice())
    

    Mutating Methods

    Các methods có thể viết dưới dang mutating, và cho phép bạn thay đổi case của chính self:

    enum DeviceMode {
        case metting
        case outdoor
        case silent
        case normal
    
        mutating func setSilent() {
            self = .silent
        }
    }
    var deviceMode =  DeviceMode.metting
    deviceMode.setSilent()
    print(deviceMode)
    

    Advanced Enum Usage

    Protocols

    Swift cho phép bạn sử dụng Protocols và Protocol Extensions với Enum:

    protocol CustomStringConvertible {
        var description: String { get }
    }
    
    enum DeviceMode: String, CustomStringConvertible {
        case metting
        case outdoor
        case silent
        case normal
    
        var description: String {
            return self.rawValue
        }
    }
    

    Extensions

    Bạn có thể sử dụng extension để bổ sung các properties và methods:

    enum DeviceMode: String {
        case metting
        case outdoor
        case silent
        case normal
    }
    
    extension DeviceMode {
        var volume: Int {
            switch self {
            case .metting:
                return 10
            case .outdoor:
                return 100
            case .silent:
                return 0
            case .normal:
                return 50
            }
        }
    }
    

    Use Enum for Error Handling

    Bạn có thể sử dụng Enum để định nghĩa tập hợp các lỗi có thể gặp phải.
    Khi định nghĩa lỗi Decode Data:

    enum DecodeError: Error {
      case typeMismatch(expected: String, actual: String)
      case missingKey(String)
      case custom(String)
    }
    

    Khi định nghĩa lỗi API:

    enum APIError : Error {
        // Can't connect to the server (maybe offline?)
        case connectionError(error: NSError)
        // The server responded with a non 200 status code
        case serverError(statusCode: Int, error: NSError)
        // We got no data (0 bytes) back from the server
        case noDataError
        // The server response can't be converted from JSON to a Dictionary
        case jsonSerializationError(error: Error)
        // The Argo decoding Failed
        case jsonMappingError(converstionError: DecodeError)
    }
    

    Dùng để định nghĩa HTTP status error:

    enum HttpError: String {
      case Code400 = "Bad Request"
      case Code401 = "Unauthorized"
      case Code402 = "Payment Required"
      case Code403 = "Forbidden"
      case Code404 = "Not Found"
    }
    

    Trên đây là những gì tìm hiểu và sưu tầm được, nếu có gì sai sót mong các bạn bổ sung giúp mình :)

    Nguồn:


Hãy đăng nhập để trả lời
 

Có vẻ như bạn đã mất kết nối tới LaptrinhX, vui lòng đợi một lúc để chúng tôi thử kết nối lại.