С выходом
Swift 6.2 появился новый мощный инструмент для наблюдения за изменениями в
@Observable моделях. Сейчас расскажу, как это работает и чем отличается от предыдущих подходов.
Что изменилось:
Раньше мы использовали
withObservationTracking с его неудобным
API и семантикой
will set. Теперь появился объект
Observations, который создает
AsyncSequence для отслеживания изменений свойств.
Пример:
Допустим, у нас есть модель счетчика:
@Observable
class Counter {
var count = 0
var name = "Счетчик"
}
Старый подход:
class CounterObserver {
func observeOldWay(counter: Counter) {
withObservationTracking {
print("Текущее значение: \(counter.count)")
} onChange: {
self.observeOldWay(counter: counter) // Рекурсивный вызов
}
}
}
Новый подход:
class CounterObserver {
func observeNewWay(counter: Counter) {
Task { [weak self] in
let values = Observations { [weak self] in
guard let self else { return "" }
// Наблюдаем за count и name, но возвращаем форматированную строку
return "\(self.counter.name): \(self.counter.count)"
}
for await value in values {
print("Обновление: \(value)")
// Обновляем UI или выполняем другую логику
}
}
}
}
Еще один пример:
class UserProfileManager {
@Observable class UserProfile {
var username: String
var email: String
var isOnline: Bool
}
func startObservingProfile() {
Task { [weak self] in
let profileUpdates = Observations { [weak self] in
guard let self else { return false }
// Наблюдаем за несколькими свойствами
let status = self.userProfile.isOnline
let name = self.userProfile.username
return (status, name)
}
for await (isOnline, username) in profileUpdates {
await self?.updateUserInterface(isOnline: isOnline, username: username)
}
}
}
}
Преимущества нового подхода:
- Более чистый код: никакой рекурсии.
- AsyncSequence: интегрируется с современным асинхронным Swift.
- Гибкость: можно возвращать любой тип данных.
- Автоматическое отслеживание: наблюдаются все свойства, доступные в closure.
Вывод:
Observations существенно упрощает отслеживание изменений данных по сравнению с предыдущими подходами. Теперь не нужно писать рекурсивные вызовы, достаточно создать асинхронную последовательность и обрабатывать обновления в цикле.