Skip to Content
Swift📘 Ngôn ngữ SwiftProperty Observers

Property Observers trong Swift

1. Giới thiệu

Property observers cho phép theo dõi và phản hồi khi giá trị của property thay đổi.

2. willSet và didSet

struct StepCounter { var steps: Int = 0 { willSet { print("Sắp thay đổi từ \(steps) thành \(newValue)") } didSet { print("Đã thay đổi từ \(oldValue) thành \(steps)") if steps > 10000 { print("🎉 Chúc mừng! Bạn đã đi hơn 10,000 bước!") } } } } var counter = StepCounter() counter.steps = 5000 // Sắp thay đổi từ 0 thành 5000 // Đã thay đổi từ 0 thành 5000 counter.steps = 12000 // Sắp thay đổi từ 5000 thành 12000 // Đã thay đổi từ 5000 thành 12000 // 🎉 Chúc mừng! Bạn đã đi hơn 10,000 bước!

3. Custom Parameter Names

struct Temperature { var celsius: Double = 0 { willSet(newTemperature) { print("Nhiệt độ sẽ thay đổi thành \(newTemperature)°C") } didSet(previousTemperature) { let diff = celsius - previousTemperature print("Thay đổi: \(diff > 0 ? "+" : "")\(diff)°C") } } } var temp = Temperature() temp.celsius = 25 // Nhiệt độ sẽ thay đổi thành 25.0°C // Thay đổi: +25.0°C

4. Validation với didSet

struct User { var age: Int = 0 { didSet { if age < 0 { age = 0 print("Tuổi không thể âm!") } else if age > 150 { age = oldValue print("Tuổi không hợp lệ!") } } } var email: String = "" { didSet { email = email.lowercased().trimmingCharacters(in: .whitespaces) } } var username: String = "" { didSet { if username.count > 20 { username = String(username.prefix(20)) } } } } var user = User() user.age = -5 // Tuổi không thể âm! → age = 0 user.email = " JOHN@Email.COM " // → "john@email.com" user.username = "this_is_a_very_long_username_that_exceeds_limit" // → "this_is_a_very_long_"

5. UI Updates

class ViewController { var score: Int = 0 { didSet { updateScoreLabel() if score != oldValue { animateScoreChange() } } } var isLoading: Bool = false { didSet { if isLoading { showLoadingIndicator() } else { hideLoadingIndicator() } } } func updateScoreLabel() { print("Score: \(score)") } func animateScoreChange() { print("✨ Animating...") } func showLoadingIndicator() { print("⏳ Loading...") } func hideLoadingIndicator() { print("✅ Done!") } }

6. Trong Class với Inheritance

class Parent { var value: Int = 0 { didSet { print("Parent: value = \(value)") } } } class Child: Parent { override var value: Int { didSet { // Parent's didSet được gọi trước print("Child: value = \(value)") } } } let child = Child() child.value = 10 // Parent: value = 10 // Child: value = 10

7. Kết hợp với Computed Properties

struct Settings { private var _volume: Int = 50 var volume: Int { get { _volume } set { let oldVolume = _volume _volume = min(100, max(0, newValue)) if _volume != oldVolume { print("Volume changed: \(oldVolume)\(_volume)") } } } }

8. Ví dụ thực tế: Shopping Cart

struct CartItem { var name: String var price: Double var quantity: Int { didSet { if quantity < 0 { quantity = 0 } print("\(name): số lượng = \(quantity)") } } } class ShoppingCart { var items: [CartItem] = [] { didSet { updateBadgeCount() saveToLocalStorage() } } var discount: Double = 0 { willSet { print("Áp dụng mã giảm giá: \(newValue * 100)%") } didSet { recalculateTotal() } } func updateBadgeCount() { print("Badge: \(items.count)") } func saveToLocalStorage() { print("Saved to storage") } func recalculateTotal() { print("Recalculating...") } }

📝 Tóm tắt

  • willSet - gọi trước khi thay đổi, newValue là giá trị mới
  • didSet - gọi sau khi thay đổi, oldValue là giá trị cũ
  • Có thể đặt tên custom cho parameters
  • Dùng cho validation, UI updates, logging
  • Không gọi khi khởi tạo init
Last updated on