Phần 1: Optional là gì?, tại sao luôn có nhiều dấu ? và ! trong các project Swift?

Chắc hẳn các bạn đã được nghe rất nhiều từ những lập trình viên Swift nói về sự tuyệt vời của Optional, một trong những đặc điểm cơ bản của ngôn ngữ lập trình Swift. Có thể nói, nếu bạn không hiểu và nắm rõ được Optional, thì bạn mới chỉ nắm đc khoảng 20% ngôn ngữ Swift thôi, và tôi tin là sau khi bạn nắm vững được nó, bạn sẽ không muốn chuyển sang ngôn ngữ lập trình nào mà không hỗ trợ tính năng này nữa. Nếu bạn đã từng bị khách hàng, đặc biệt khách hàng Nhật phàn nàn về việc app crash, chỉ vì code của bạn cho chèn giá trị nil vào một NSDictionary hay một đoạn text ở UILabel hiển thị nil, bạn sẽ càng trở nên yêu Optional hơn.

Hãy bắt đầu bằng một ví dụ nhỏ, đầu tiên các bạn tải Playground project này về và mở nó lên. Ở đây bạn muốn tạo một model thể hiện một người, chúng ta đặt tên model đó là Person, và tất nhiên là người phải có tên, tên họ và tên đệm rồi:

struct Person {
    let givenName: String
    let familyName: String
    let middleName: String
}

 

Từ đây tôi tạo ra một đối tượng thể hiện chính bản thân mình, do tôi không có tên đệm nên ở trường middleName tôi để nil:

let me = Person(givenName: "Khanh", familyName: "Nguyen", middleName: nil)

ngay lập tức tôi nhận được thông báo lỗi như sau:

Nil is not compatible with expected argument type 'String'.

Ở đây Swift đang cảnh báo chúng ta rằng: "Này, middleName không thể nil được vì lúc khai báo ông có nói rằng nó "có thể nil" đâu? ". Và đó là lúc Optional ra đời.

Chúng ta khai báo lại struct Person như sau:

struct Person {
    let givenName: String
    let familyName: String
    let middleName: String?
}

Ở đây tại thuộc tính middleName chúng ta có thêm dấu ? ở cuối cùng, điều đó có nghĩa là gì, nghĩa là chúng ta đã thông báo trước cho Swift rằng, giá trị của thuộc tính middleName có thể là nil hoặc là kiểu String, một trong hai.

Quay lại đoạn code trên thì thông báo lỗi đã biến mất.

Tiếp theo chúng ta hay cũng tạo ra một computed property của struct Person tên là displayName, thuộc tính này trả về tên đẩy đủ của một người, bao gồm cả tên đệm (nếu có). Ví dụ: Nếu tôi tên là Nguyễn Khánh, thì sẽ trả về Nguyễn Khánh, nếu có tên đệm thì sẽ là Nguyễn Duy Khánh.

struct Person {
    let givenName: String
    let familyName: String
    let middleName: String?
    
    var displayName: String {
        return givenName + " " + middleName + " " + familyName
    }
}

Và ở dưới thì chúng ta thấy Swift lại hiển thị thông báo lỗi:

Swift sẽ hiển thị một thông báo và một gợi ý ở dưới, nó nói rằng chúng ta phải thêm dấu ! vào sau thuộc tính middleName. Ở đây sẽ có rất nhiều bạn làm theo và tưởng như vậy là mọi thứ đã ổn, không phải vậy, đáp án đúng ở đây là KHÔNG LÀM THEO GỢI Ý NÀY.

Tại sao lại vậy?

Dấu ! trong Swift được dùng để "force unwrapping" một biến optional, có nghĩa là bạn cam đoan với trình biên dịch rằng thuộc tính này sẽ luôn có giá trị hay còn gọi là KHÔNG BAO GIỜ NIL.Và nếu bạn không chắc chắn rằng thuộc tính này luôn có giá trị, app sẽ crashes luôn khi đang chạy và điều này là không vui chút nào. Lấy ví dụ khi tôi print thuộc tính middleName:

print(middleName!)

Nếu thuộc tính middleName của tôi có giá trị là "Duy", ứng dụng sẽ chạy bình thường, trên console sẽ hiện ra chuỗi "Duy", tuy nhiên vì một lý do nào đó, mất mạng hay lỗi API chẳng hạn mà thuộc tính middleName của tôi không thể nhận được giá trị, hoặc đơn giản là tôi quên gán giá trị cho nó. Ngay lập tức ứng dụng sẽ bị crashes hay theo cách gọi của chúng tôi là "Chết app". Điều này luôn luôn xảy ra trong quá trinh lập trình, và tôi dám chắc rằng rất nhiều người sẽ không hiểu vì sao.

 

Nói đến đây thì bạn đã hình dung được tính chất và vai trò của Optional rồi, và để giải quyết vấn đề trên thì chúng ta có thể làm theo một cách đơn giản, đó là đặt điều kiện cho thuộc tính middleName:

if middeName != nil {
print(middleName)
}

Như vậy là vấn đề sẽ được giải quyết, tuy nhiên với những thuộc tính phức tạp, hay những project có luồng dữ liệu lớn thì cách này chưa phải là tối ưu, và thật tuyệt vời là Swift đã cung cấp cho ta 2 công cụ tuyệt vời để đảm bảo sự an toàn cho app, đó chính là "if let" và "guard". Để tìm hiểu tính năng và cách sử dụng 2 công cụ này, chúng ta hãy cùng đón chờ tới phần 2 của bài viết nhé.