Key-Value Observing — это механизм в Cocoa/Cocoa Touch, позволяющий объектам наблюдать за изменениями свойств других объектов. Это реализация паттерна Observer в экосистеме Apple.
Key-Value Monitoring — это более общее понятие, включающее KVO и другие механизмы наблюдения за изменениями значений. В iOS разработке термин KVM используется реже, обычно говорят именно о KVO.
class User: NSObject {
@objc dynamic var name: String = "John Doe" // 1. Делаем свойство observable
}
let user = User()
// 2. Создаем наблюдатель
var observation: NSKeyValueObservation?
observation = user.observe(\.name, options: [.old, .new]) {
(object, change) in
print("Name changed from \(change.oldValue) to \(change.newValue)")
}
user.name = "Jane Smith" // 3. Триггерим изменение
Наблюдаемое свойство:
@objc dynamic
Наблюдатель (Observer):
NSKeyValueObservation
Опции наблюдения:
.new
— получать новое значение.old
— получать старое значение.initial
— получить начальное значение сразуСвязывание данных:
Наблюдение за системными свойствами:
// Наблюдение за состоянием UIScrollView
scrollView.observe(\.contentOffset) { scrollView, _ in
print("Content offset: \(scrollView.contentOffset)")
}
Интеграция с legacy-кодом:
Сложные зависимости между свойствами:
class Account: NSObject {
@objc dynamic var balance: Double = 0
@objc dynamic var isOverdrawn: Bool = false
private var observations = [NSKeyValueObservation]()
init() {
super.init()
observations.append(observe(\.balance) { [weak self] _, _ in
self?.isOverdrawn = (self?.balance ?? 0) < 0
}
}
}
Автоматические уведомления: Не нужно вручную вызывать методы при изменении
Низкая связанность: Наблюдателю не нужно знать о наблюдаемом объекте
Множественные наблюдатели: Можно подписать несколько объектов на одно свойство
Требования к коду:
Проблемы с памятью:
Дедлоки: KVO notifications могут приходить синхронно
Отладка:
Property Observers:
var score: Int = 0 {
didSet {
print("Score changed from \(oldValue) to \(score)")
}
}
Combine Framework:
@Published var username: String = ""
$username.sink { print("Username changed to \($0)") }
RxSwift/ReactiveSwift: Реактивные расширения для наблюдения за изменениями
Делегаты и замыкания: Более явные, но более многословные подходы
Всегда храните наблюдения:
private var observations = [NSKeyValueObservation]()
func setupObservations() {
observations.append(object.observe(\.property) { _, _ in
// handle change
})
}
Используйте .initial для начальной настройки:
observe(\.value, options: [.new, .initial]) { _, change in
// Вызовется сразу с текущим значением
}
Будьте осторожны с потоками: KVO notifications могут приходить с любого потока
Отписывайтесь при необходимости: Установите observations = [] когда они больше не нужны
KVO — это мощный механизм наблюдения за изменениями свойств, унаследованный от Objective-C. В современной Swift-разработке он используется реже из-за появления более безопасных альтернатив (Combine, property observers), но остается важным для:
При использовании KVO важно помнить о: