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°C4. 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 = 107. 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,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
Last updated on
Swift