Optional trong Swift

Giới thiệu

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. Optional là một khái niệm mới trong ngôn ngữ lập trình Swift. Với việc sử dụng optional, ngôn ngữ Swift được Apple giới thiệu là ngôn ngữ “an toàn” hơn so với ngôn ngữ Objective-C trước đó. Nếu bạn đã từng bị khách hàng 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 Dictionary, truy cập vào 1 object đã giải phóng, hay một đoạn text ở UILabel hiển thị nil, Optional sẽ giúp bạn trong những trường hợp này. Optional sinh ra để xử lý với các trường hợp object ko có giá trị.

Khai báo Optional

Khai báo Integer Optional

var perhapsInt: Int?

Khai báo String Optional

var perhapsStr: String?

Khai báo Optional

var variableName: ValueType?

ValueType ở đây có thể là String, Integer, Float, hay 1 custom object ... Trong Swift, khi khởi tạo các biến, các biến này mặc định sẽ được khởi tạo dưới dạng non-optional, tức là phải được gán giá trị mà không được để nil. Nếu chúng ta gán giá trị nil cho các biến non-optional này, trình biên dịch sẽ thông báo lỗi. Ví dụ:

var str: String //compile error 

Biến str là kiểu String, kiểu non-optional nhưng ko gán giá trị mặc định nên Xcode sẽ báo lỗi

var str: String = “Hello Swift” // OK
str = nil // biên dịch lỗi 

Như trên biến str có kiểu String, đây là kiểu non-optional nên ta phải gán giá trị mặc định cho nó là "Hello Swift", dòng bên dưới ta gán str = nil trong khi str là kiểu non-optional nên Xcode sẽ báo lỗi trong trường hợp này. Khai báo dạng optional:

var str: String? = “Hello Swift” // OK
str = nil // OK 

Forced Unwrapping

If you defined a variable as optional, then to get the value from this variable, you will have to unwrap it. This just means putting an exclamation mark at the end of the variable.

Let's take a simple example − Nếu định nghĩa một biến kiểu optional, sau đó nếu ta muốn lấy giá trị từ biến này, chúng ta phải unwrap nó. Ở đây ta sẽ có 2 khái niệm là wrap và unwrap, ta xem ví dụ sau:

var msg: String? = "Hello Swift"

Ở đây biến msg có kiểu dữ liệu là String?, Kiểu dữ liệu String thì chúng ta đều đã biết, vậy còn String? nó là 1 wrap của kiểu String, nó là kiểu String + nil, do đó 2 kiểu String và String? là khác nhau, muốn lấy giá trị của msg ta phải unwrap nó tức là lấy kiểu String của nó. Chạy đoạn code sau: import Cocoa

var myString:String?

myString = "Hello, Swift!"

if myString != nil {
   println(myString)
}else {
   println("myString has nil value")
}

Ta sẽ nhận được output như sau:

Optional("Hello, Swift!")

Bây giờ ta sẽ force unwrap để lấy được giá trị đúng của myString

import Cocoa

var myString:String?

myString = "Hello, Swift!"

if myString != nil {
   println( myString! )
}else {
   println("myString has nil value")
}

Kết quả:

Hello, Swift!

Vậy ta force unwrap bằng cách thêm ! sau biến cần unwrap Tuy nhiên việc force unwrap là việc nên tránh, vì trường hợp nếu biến force unwrap đó nil thì sẽ gây crash app

Automatic Unwrapping

Ví dụ:

import Cocoa

var myString:String!

myString = "Hello, Swift!"

if myString != nil {
   println(myString)
}else {
   println("myString has nil value")
}

Ở đây biến myString được khai báo kiểu String!, khi ta gọi hàm println(myString) thì biến myString này đã tự động unwrap thành kiểu String

Optional Binding

Sử dụng optional binding để check xem biến optional có giá trị hay ko, để có những xử lý tương ứng tránh bị crash app

var myString:String?

myString = "Hello, Swift!"

if let yourString = myString {
   println("Your string has - \(yourString)")
}else {
   println("Your string does not have a value")
}

Kết quả:

Your string has - Hello, Swift!

Optional Chaining

Ví dụ sau:

class Stock = {

    var code: Sring?

    var price: Double?

}

func findStockCode(company:String) -> Stock? {

    if(company == “Apple”) {

        let appl: Stock = Stock()

        appl.code = “APPL”

        appl.price = 90.32

        return appl

    }else if (company == “Google”) {

        let goog: Stock = Stock()

        goog.code = “GOOG”

        goog.price = 90.32

        return appl

    }

    return nil
}

if let stock = findStockCode(“Apple”) {

    if let sharePrice = stock.price {

        let totalPrice = sharePrice * 100

        println(totalPrice)

    }

}

Ta có thể sử dụng optional chaining làm cho code ngắn gọn hơn như sau:

if let sharePrice = findStockCode(“Apple”)?.price {

    let totalPrice = sharePrice * 100

    println(totalPrice)

}

Kết luận

Trong bài viết này tôi đã giới thiệu đến các bạn khái niệm optional, một khái niệm mới của Swift giúp cho lập trình viên đảm bảo code của mình an toàn hơn khi phải check nil với các biến trước khi thực hiện thao tác nào đó trên biến đó, điều này sẽ giúp giảm thiểu tình trạng crash app. Để hiểu thêm các bạn có thể tham khảo thêm ở các tài liệu sau: https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html http://www.appcoda.com/beginners-guide-optionals-swift/ https://www.tutorialspoint.com/swift/swift_optionals.htm