Property Observers
1. Giới thiệu
Phần tiêu đề “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
Phần tiêu đề “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
Phần tiêu đề “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°C4. Validation với didSet
Phần tiêu đề “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 = 0user.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
Phần tiêu đề “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
Phần tiêu đề “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 = 107. Kết hợp với Computed Properties
Phần tiêu đề “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
Phần tiêu đề “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
Phần tiêu đề “📝 Tóm tắt”willSet- gọi trước khi thay đổi,newValuelà giá trị mớididSet- gọi sau khi thay đổi,oldValuelà 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