Tiếp theo bài viết lần trước, hôm nay tôi sẽ giới thiệu cho các bạn 2 phương thức giúp bạn nắm rõ và sử dụng Optional trong Swift thành thạo hơn, đó chính là If let và guard.

If let

Một khối lệnh If let có cấu trúc như sau:

if let x = y { // Khởi tạo một đối tượng x = đối tượng optional y
    A(x) // Sử dụng biến non-optional x
}

Ở đây bạn có thể hiểu khối lệnh trên như sau: Nếu y là có giá trị không nil, gán nó vào x và thực thi A(x), điều này đảm bảo rằng x là một đối tượng không nil.

Quay lại ví dụ, chúng ta có thể khai báo lại đối tượng displayName như sau:

var displayName: String {
    if let middleName = middleName {
        return givenName + " " + middleName + " " + familyName
    }
    return givenName + " " + familyName
}

 

Ở đây chúng ta khai báo một đối tượng middleName mới và gán middleName cũ vào, bạn có thể đặt tên khác nhưng ở đây tôi đặt tên 2 biến giống nhau code gọn và dễ đọc hơn. Điều quan trọng là chúng ta có một biến "sạch sẽ" để đảm bảo ko còn tồn tại nil trong khối lệnh này.

Guard

Từ Swift 2.0 thì Apple đã giới thiệu thêm một công cụ tuyệt vời nữa, đó là Guard, cấu trúc của một khối lệnh Guard như sau:

guard let x = y else { // Where y is Optional
    A(y) // Do something with y as nil
}
// Do something with non-Optional x

Cấu trúc này hơi ngược một chút so với if let, nếu y không nil, chúng ta gán nó vào x, còn nếu không, khối lệnh else sẽ thực thi, ở dưới cùng, chúng ta làm những gì mình muốn với x đã được đảm bảo là không nil.

var displayName: String {
    guard let middleName = middleName else {
        return givenName + " " + familyName
    }
    return givenName + " " + middleName + " " + familyName
}

 

Nhìn qua thì guard không khác gì mấy so với if let, vậy thì tại sao tôi lại gọi đây là một công cụ tuyệt vời, và  tại sao tôi thường sử dụng guard hơn là if let?. Chúng ta hãy thử đi qua một ví dụ phức tạp hơn để hiểu rõ về điều này.

Khi chúng ta viết app, hầu như đều phải làm việc với hệ thống API backend. API trả về dữ liệu cho chúng ta từ server (thường dưới dạng JSON), và chúng ta phải convert chúng thành đối tượng để làm việc trên phía client. Ở ví dụ Person, tôi sẽ mô phỏng thành một JSON dictionary được trả về từ API. Đầu tiên hãy làm bằng if let:

init?(dictionary: NSDictionary) {
    if let givenName = dictionary["given_name"] as? String,
        let familyName = dictionary["family_name"] as? String {
            self.givenName = givenName
            self.familyName = familyName
    } else {
        return nil
    }
    self.middleName = dictionary["middle_name"] as? String
}

 

Ở đây if let cho bạn khởi tạo nhiều giá trị cùng một lúc, nhưng nhìn chung nó vẫn khá phức tạp với một task đơn giản. Đầu tiên chúng ta kiểm tra nếu dictionary["given_name"] là kiểu String và gán vào givenName. Tương tự với dictionary["family_name"] . Nếu cả hai đối tượng trên đều không nil, thì ta gán chúng vào property tương ứng, còn nếu không sẽ return nil và khởi tạo thất bại. Cuối cùng là đặt middleName ra ngoài khối if let.

Chúng ta có thể tối ưu task trên với guard như sau:

init?(dictionary: NSDictionary) {    
    guard
        let givenName = dictionary["given_name"] as? String,
        let familyName = dictionary["family_name"] as? String
    else { return nil }
    
    self.givenName = givenName
    self.familyName = familyName
    self.middleName = dictionary["middle_name"] as? String
}

Trước khi đi vào phân tích code, chúng ta có thể dễ dang nhận ra với guard, code trở nên sáng sửa và dễ nhìn hơn so với if let.

Tương tự với if let thì chúng ta gán giá trị cho givenName và familyName. Tuy nhiên điều khác biệt ở đây là nếu hai thuộc tính trên không phải kiểu String, chương trình sẽ đi vào else và trả về nil, điều này có nghĩa rằng, các đối tượng trả về phải đi qua một cửa bảo vệ "guard" để đảm bảo rằng chúng không nil. Nếu không sẽ bị "giữ lại" ở khối lệnh else. Sau khi đi qua được hàng rào an ninh guard, chúng ta thực hiện gán giá trị bình thường và làm những thứ bạn muốn mà không phải lo crash app nữa. 

Có thể nói so với if let, guard an toàn và logic dễ hiểu hơn rất nhiều, về mặt cú pháp cũng trong sáng và rõ ràng hơn, điều này rất hữu dụng khi bạn làm với những task phức tạp như JSON ở trên.

Lời kết

Qua hai bài viết trên thì tôi đã giới thiệu cho các bạn về Optional, một tính năng rất cơ bản và quan trọng của Swift, hy vọng rằng các bạn sẽ nắm vững được nó và sử dụng một cách linh hoạt để làm cho ứng dụng của mình trở nên an toàn hơn.