[Swift] Nâng cao khả năng xử lý dữ liệu trong ứng dụng với Ép kiểu và Kiểm tra kiểu dữ liệu

Swift cơ bản: Ép kiểu và Kiểm tra kiểu - Nâng cao khả năng xử lý dữ liệu trong ứng dụng của bạn!

Chào các bạn, hôm nay chúng ta sẽ cùng tìm hiểu về hai kỹ thuật quan trọng trong Swift: Ép kiểu (Type Casting)Kiểm tra kiểu (Type Inspection). Nắm vững hai kỹ thuật này sẽ giúp bạn làm việc linh hoạt và an toàn hơn với các kiểu dữ liệu khác nhau, từ đó xử lý các tình huống phức tạp một cách hiệu quả.

1. Ép kiểu (Type Casting)

Tưởng tượng bạn đang xây dựng một ứng dụng quản lý thú cưng. Bạn có một function getClientPet() trả về một con vật thuộc kiểu Animal (kiểu cha). Tuy nhiên, bạn cần biết chính xác con vật đó là Turtle, Cat hay Bird để thực hiện các hành động chăm sóc phù hợp.

class Animal {}
class Turtle: Animal { var name: String = "" }
class Cat: Animal { var boxSize: String = "" }
class Bird: Animal { var featherColor: String = "" }

func getClientPet() -> Animal {
    // Giả sử ở đây trả về một con mèo
    return Cat() 
}

func cleanTerrarium(turtle: Turtle) {
    print("Dọn dẹp bể cá cho \(turtle.name)")
}

func cleanLitterBox(cat: Cat) {
    print("Dọn dẹp hộp vệ sinh kích cỡ \(cat.boxSize)")
}

func cleanCage(bird: Bird) {
    print("Dọn dẹp lồng và nhặt lông màu \(bird.featherColor)")
}

Để làm được điều này, chúng ta sử dụng ép kiểu. Có hai loại ép kiểu:

a) Ép kiểu có điều kiện (Conditional Cast): Sử dụng toán tử as? để thử ép kiểu. Nếu thành công, bạn sẽ nhận được đối tượng thuộc kiểu con mong muốn. Nếu không, bạn sẽ nhận được nil.

let pet = getClientPet()

if let turtle = pet as? Turtle {
    cleanTerrarium(turtle: turtle)
} else if let cat = pet as? Cat {
    cleanLitterBox(cat: cat)
} else if let bird = pet as? Bird {
    cleanCage(bird: bird)
}

b) Ép kiểu bắt buộc (Forced Cast): Sử dụng toán tử as! để buộc ép kiểu. Nếu ép kiểu không thành công, ứng dụng sẽ crash. Chỉ nên sử dụng khi bạn hoàn toàn chắc chắn về kiểu dữ liệu.

let laurasCat = getClientPet() as! Cat // Biết chắc chắn là mèo
print("Con mèo của Laura có kích cỡ hộp vệ sinh là: \(laurasCat.boxSize)")

2. Kiểm tra kiểu (Type Inspection)

Đôi khi bạn cần kiểm tra kiểu dữ liệu của một biến trước khi sử dụng. Ví dụ, bạn có một mảng chứa nhiều kiểu dữ liệu khác nhau và muốn thực hiện các hành động khác nhau tùy thuộc vào kiểu của mỗi phần tử.

Swift cung cấp toán tử is để kiểm tra kiểu. Toán tử này trả về true nếu đối tượng thuộc kiểu được chỉ định, ngược lại trả về false.

let data: [Any] = [10, "Hello", true, Cat()]

for item in data {
    if item is Int {
        print("Đây là số nguyên")
    } else if item is String {
        print("Đây là chuỗi")
    } else if item is Bool {
        print("Đây là kiểu Bool")
    } else if item is Cat {
        print("Đây là con mèo")
    }
}

3. Kiểu dữ liệu đặc biệt: Any và AnyObject

Swift cung cấp hai kiểu đặc biệt: AnyAnyObject. Any có thể đại diện cho bất kỳ kiểu dữ liệu nào, còn AnyObject chỉ đại diện cho kiểu dữ liệu class.

var mixedData: [Any] = [42, "Swift", true, Dog()]
var classData: [AnyObject] = [Cat(), Dog()]

Lưu ý: Nên hạn chế sử dụng AnyAnyObject khi không thực sự cần thiết, vì chúng làm giảm tính an toàn của kiểu dữ liệu.

4. Kết hợp Ép kiểu và Kiểm tra kiểu

Thường bạn sẽ kết hợp hai kỹ thuật này để xử lý dữ liệu hiệu quả.

let myPet = getClientPet()

if myPet is Cat {
    let cat = myPet as! Cat
    cleanLitterBox(cat: cat)
}

5. Nhắc lại về Chuyển đổi kiểu dữ liệu

a) Chuyển đổi chuỗi sang số:

Sử dụng initializer của kiểu số (Int, Double,...) để chuyển đổi chuỗi sang số. Nếu chuỗi không hợp lệ, initializer sẽ trả về nil.

let stringNumber = "123"
if let number = Int(stringNumber) {
    print("Số nguyên: \(number)")
} else {
    print("Chuỗi không hợp lệ!")
}

let stringDouble = "3.14"
if let doubleNumber = Double(stringDouble) {
    print("Số thực: \(doubleNumber)")
} else {
    print("Chuỗi không hợp lệ!")
}

b) Chuyển đổi số sang chuỗi:

Sử dụng initializer String(number) để chuyển đổi số sang chuỗi.

let number = 100
let stringFromNumber = String(number)
print("Chuỗi từ số nguyên: \(stringFromNumber)")

let doubleNumber = 12.34
let stringFromDouble = String(doubleNumber)
print("Chuỗi từ số thực: \(stringFromDouble)")

Type Casting là kỹ thuật chuyển đổi giữa các kiểu dữ liệu có quan hệ kế thừa với nhau (ví dụ như Cat là con của Animal). Trong khi đó, việc sử dụng initializer là chuyển đổi giá trị của một kiểu dữ liệu sang một kiểu dữ liệu hoàn toàn khác, không có quan hệ kế thừa.

Ví dụ:

  • Int(someDouble) không phải ép kiểu mà là khởi tạo một Int mới từ giá trị của someDouble.
  • String(someInt) không phải ép kiểu mà là khởi tạo một String mới từ giá trị của someInt.

Type Conversion (Chuyển đổi kiểu dữ liệu)

Type Conversion là quá trình chuyển đổi giá trị của một kiểu dữ liệu sang một kiểu dữ liệu khác. Quá trình này có thể bao gồm:

  • Ép kiểu (Type Casting): Chuyển đổi giữa các kiểu dữ liệu có quan hệ kế thừa.
  • Chuyển đổi giá trị (Value Conversion): Chuyển đổi giá trị của một kiểu dữ liệu sang một kiểu dữ liệu khác, không có quan hệ kế thừa (ví dụ: Double -> Int, chuỗi -> số).

Khi sử dụng initializer như Int(someDouble) hay String(someInt), bạn đang thực hiện Value Conversion.

Tóm lại, "Type Conversion" là thuật ngữ bao quát hơn, bao gồm cả "Type Casting" và "Value Conversion".

Hy vọng bài viết này giúp bạn hiểu rõ hơn về Ép kiểu và Kiểm tra kiểu trong Swift, cũng như cách chuyển đổi giữa chuỗi và số. Hãy luyện tập và áp dụng chúng vào các dự án của bạn nhé!