Chúng ta sẽ tìm hiểu về Enum. Enumerations là một trong những design pattern có trong nhiều ngôn ngữ lập trình khác nhau như C++,C#,Objective-C. Mặc dù, nó khá giống các ngôn ngữ khác nhưng enumeration trong Swift có khá nhiều điểm khác biệt và linh hoạt. Bây giờ chúng ta sẽ bắt đầu tìm hiểu điều đó.
Để bắt đầu cho bài hướng dẫn này, các bạn nên sử dụng Xcode Playground để thực hành code theo các ví dụ trong bài, nó giúp bạn sẽ dễ hiểu và nhớ lâu hơn.

Enumeration là gì ?

Enumeration không phải là một khái niệm mới và chắc chắn sẽ không riêng gì ngôn ngữ Swift có nhưng trong Swift, enumeration khá mạnh.

Trong Swift, enumeration là một lớp giá trị, nó dùng để định nghĩa ra danh sách các giá trị. Ví dụ về các trang thái của kết nối mạng, có thể có các trạng thái sau:

  • Disconnected
  • Connecting
  • Connrcted

Theo ví dụ trên chúng ta sẽ định nghĩa một enumeration như sau:

enum ConnectionState {
    case Unknown
    case Disconnected
    case Connecting
    case Connected
}

Chúng ta sẽ dùng từ khoá enum để mô tả một enumeration và case để mô tả từng trị trong enum với tên là ConnectionState. Đối với ngôn ngữ C, Objective-C thì một enum có thể được mô tả bằng nhiều tên khác nhau, Nhưng với Swift thì chỉ có duy nhất một tên vì thế mà nó trở nên an toàn và không phức tạp trong code. Ngoài ra, Enumeration có thể chỉ định một kiểu dữ liệu nào đó cho toàn bộ các phần tử của nó, Bây giờ ta sẽ chỉ định enum ConnectionState với kiểu Int. Khi đó các phần tử của ConnectionState phải được gán kiểu Int, nếu gán kiểu khác Xcode sẽ thông báo lỗi.

Ví dụ 1:

enum ConnectionState: Int {
    case Unknown = -1
    case Disconnected = 0
    case Connecting = 1
    case Connected = 2
}

Lưu ý: Trong các phần tử của một enum không được có giá trị giống nhau. Bạn yên tâm Xcode sẽ báo lỗi nếu xảy ra giống nhau. Nếu chúng ta chỉ gán giá trị cho một phần tử, khi đó Swift sẽ tự động gán ngầm giá trị cho các phần tử còn lại, lấy giá trị chuẩn từ phần tử Unknown = -1 và tăng tự động giá trị lên. nó sẽ gián như ví dụ 1.

Ví dụ

enum ConnectionState: Int {
    case Unknown = -1
    case Disconnected
    case Connecting
    case Connected
}

Sử dụng

Sử dụng ConnectionState cũng tương tự như các kiểu dữ liệu khác trong Swift. Theo ví dụ trước chúng ta đã mô tả ConnectionState, bây giờ chúng ta sử dụng nó như sau:

var connectionState = ConnectionState.Connecting

Giá trị của connectionState là ConnectionState.Connecting. Kiểu tự suy luận của Swift rất là tiện dụng khi áp dụng với enum, bởi vì khi khai báo hay gián trị cho biến connectionState thì chỉ cần làm như sau:

connectionState = .Connected

Enumeration thường được dùng với if hay switch, Lưu ý khi dùng với Switch phải mô tả đầy đủ các phần tử trong Switch không nó sẽ báo lỗi, và dùng default nếu cần thiết.

Ví dụ:

enum ConnectionState {
    case Unknown
    case Disconnected
    case Connecting
    case Connected
}
 
var connectionState = ConnectionState.Connecting
 
connectionState = .Connected
 
switch connectionState {
    case .Disconnected:
        println("Disconnected")
    case .Connecting:
        println("Connecting")
    case .Connected:
        println("Connected")
    default:
        println("Unknown State")
}

Thêm ví dụ về sử dụng enum :

func canConnect(connectionState: Connectionng nhưState) -> Bool {
    var result = false
     
    switch connectionState {
        case .Connected(let port):
            if port == 3000 {
                result = true
            }
        default:
            result = false
    }
     
    return result
}
 
let state = ConnectionState.Connected(3000)
 
if canConnect(state) {
    // ...
}

Khả năng liên kết giá trị

Một trong những tính năng hấp dẫn khác của enum trong Swift đó là liên kiết giá trị(Associated Values). Đây là tính năng quan trọng được sử dụng nhiều. Mỗi thành phần của enum có thể được mô tả thêm một giá trị liên kết nào đó(Associated value). Giá trị liên kết này là một trong những tính năng linh hoạt vì nó có thể bao gồm nhiều kiểu dữ liệu khác nhau được gắn với 1 thành phần trong enum. Để hiểu rõ hơn chúng ta tham khảo ví dụ sau:

Ví dụ:

enum ConnectionState {
    case Unknown
    case Disconnected
    case Connecting(Int, Double)
    case Connected(Int)
}

Quan trọng ở đây chúng ta phải hiểu được liên kết giá trị(assciated value) là một liên kết hay là một liên kết với một số giá trị nào đó thông qua thành phần của một enum. Để hiểu rõ hơn, Chúng ta sẽ xem ví dụ sau đây.

enum Student {
  case Name(String)
  case Mark(Int,Int,Int)
}
var studDetails = Student.Name("Swift")
var studMarks = Student.Mark(98,97,95)
switch studMarks {
  case .Name(let studName):
     println("Student name is: \(studName).")
  case .Mark(let Mark1, let Mark2, let Mark3):
     println("Student Marks are: \(Mark1),\(Mark2),\(Mark3).")
  default:
     println("Nothing")
}

Hàm và Value types

Trong Swift, Enum khá tuyệt vời. Nó có thể cho phép chúng ta định nghĩa các method,

Ví dụ:

enum ConnectionState {
    case Unknown
    case Disconnected
    case Connecting(Int, Double)
    case Connected(Int)
     
    init () {
        self = .Unknown
    }
}
 
var connectionState = ConnectionState() // .Unknown

Ngoài ra chúng ta có thể định nghĩa hàm Static trong enum.

Ví dụ:

import Foundation

enum Device {
    case phone(name: String, screenSize: CGSize)
    case watch(name: String, screenSize: CGSize)
    case tablet(name: String, screenSize: CGSize)

    private static var initializers: [String: (name: String, screenSize: CGSize) -> Device] = {
	return ["phone": Device.phone, "watch": Device.watch, "tablet": Device.tablet]
    }()

    static func fromDefaults(rawValue: String, name: String, screenSize: CGSize) -> Device? {
	return Device.initializers[rawValue]?(name: name, screenSize: screenSize)
    }
}

let iPhone = Device.fromDefaults("phone", name: "iPhone SE", screenSize: CGSize(width: 640, height: 1134))
print(iPhone) //Optional(main.Device.phone("iPhone SE", (640.0, 1134.0)))

Giống như struct, enum cũng là một kiểu dữ liệu và nó chỉ chứa giá trị nào đó. Vì thế nên nó sẽ không thể tham chiếu được như class và chỉ dùng theo kiểu trị giống như struct.
Ví dụ:

var connectionState1 = ConnectionState()
var connectionState2 = connectionState1
 
connectionState1 = .Connected(1000)
 
println(connectionState1) // .Connected(1000)
println(connectionState2) // .Unknown

Sau bài này chúng ta đã tìm hiểu được nhiều điểm mạnh của enum trong Swift so với các ngôn ngữ khác. Ngoài điểm linh hoạt, làm cho code dễ hiểu, nó còn giúp chúng ta dễ bảo trì code về sau.

Đăng ký kênh youtube để ủng hộ Cafedev nha các bạn, Thanks you!