Key-Value Observing(KVO)은 지정한 객체 속성의 변경 사항을 다른 객체에 알리는 데 사용하는 코코아 프로그래밍 패턴입니다.(KeyPath, KVC, KVO에서 사용하는 Key(문자열)는 인스턴스의 속성 값에 간접적으로 접근하게 해주는 방법으로 Objective-C에서 나온 개념)
간략히 말하면 A의 속성 값이 변경되었을 때, B가 그를 알게 하는 것이에요.
KVO는 NSObject에서 상속된 클래스만이 사용할 수 있고, 앱의 모델과 뷰 처럼 논리적으로 분리된 부분 간 변경 사항을 전달하는데 유용해요.
예를 들어, Person 객체가 은행에서 본인의 계좌를 나타내는 Account 객체와 상호 작용한다고 가정해볼게요.
Person의 인스턴스는 잔액이나 이자 같은 Account 인스턴스의 특정 속성이 언제 변경되는지 알아야 할 수도 있어요.
이런 속성들이 Account의 Public 속성이라면 Person 인스턴스는 Account를 Polling(상태를 주기적으로 검사하여 조건을 만족할 때 처리를 하는 방식)하여 변화를 발견할 수 있지만, 매우 비효율적이죠.
이때 더 나은 접근 방식은 변화가 발생할 때 인터럽트를 받는 KVO를 사용하는 것이에요.
1. KVO를 사용하려면 우선 observed 객체, Account가 KVO를 준수하는지 확인해야 해요.
일반적으로 객체가 NSObject를 상속받는 경우 객체와 속성은 자동으로 KVO를 준수합니다.
그게 아니라면 클래스의 경우 속성에 대한 Key-Value Coding을 준수하도록 하여 KVO를 준수하도록 구현할 수 있어요.
2. 그다음 observer 인스턴스 Person를 observed 인스턴스 Account와 함께 등록해야 해요.
3. Person에 observer 메서드를 구현하면 Account에 등록된 Key path 중 하나가 변경될 때마다 알림을 받을 수 있고, Person은 알림에 따라 적절한 조치를 취할 수 있게 됩니다.
4. 만약 Person이 Account를 파기하는 상황, 인스턴스를 deinit 시키는 경우 같이 더 이상 알림을 원하지 않는 다면 Person 인스턴스는 Account에 observer 등록을 취소할 수 있어요.
KVO의 이점은 속성이 변경될 때 마다 알림을 보내기 위해 스키마를 구현할 필요가 없어지고, NSObject는 KVO의 기본 기능들을 제공하기 때문에 일반적으로 재정의할 필요가 거의 없습니다.
모든 observer에게 변경 알림을 제공하는 중앙 객체가 존재하는 NSNotificationcCenter와 달리 중앙 객체가 없고, 대신 변경이 이루어질 때 observed 대상에게 직접 전송됩니다.
KVO 사용해 보기
키 관찰을 위한 속성 추가
@objc dynamic modifer를 통해 관찰하고 싶은 속성을 표시할 수 있습니다.
아래는 관찰 가능한 속성을 가진 클래스입니다.
class MyObjectToObserve: NSObject {
@objc dynamic var myDate = NSDate(timeIntervalSince1970: 0) // 1970
func updateDate() {
myDate = myDate.addingTimeInterval(Double(2 << 30)) // add 68 years
}
}
옵저버 정의
옵저버 클래스의 인스턴스는 속성 변경 사항에 대한 정보를 관리해요.
옵저버를 만들 때, 관찰하려는 속성을 참조하는 키 경로로 observe(_:options:changeHandler:) 메서드를 호출해 관찰할 수 있어요.
class MyObserver: NSObject {
@objc var objectToObserve: MyObjectToObserve
var observation: NSKeyValueObservation?
init(object: MyObjectToObserve) {
objectToObserve = object
super.init()
observation = observe(
\\.objectToObserve.myDate, // MyObjectToObserve.myDate 속성 키 경로
options: [.old, .new]
) { object, change in
print("myDate changed from: \\(change.oldValue!), updated to: \\(change.newValue!)")
}
}
}
NSKeyValueObservedChange 인스턴스의 oldValue, newValue 속성을 사용해서 관찰 중인 속성의 변경 사항을 볼 수 있으며, 생략하면 속성의 변경 사항을 추적하지 않을 수 있어요.
만약 options 변수를 생략하면 신규, 기존 속성 값을 저장하지 않으며 oldValue, newValue 속성은 nil이 됩니다.
옵저버 연결
객체를 옵저버의 이니셜라이저에 전달해서 관찰하고 싶은 속성을 옵저버와 연결할 수 있어요.
let observed = MyObjectToObserve()
let observer = MyObserver(object: observed)
변경 사항에 대한 응답
updateDate 메서드를 호출하면 myDate 속성이 변경되면서 옵저버에게 변경 핸들러를 자동으로 트리거 시켜요.
observed.updateDate()
// myDate changed from: 1970-01-01 00:00:00 +0000,
// updated to: 2038-01-19 03:14:08 +0000
참고
Using Key-Value Observing in Swift
Performing Key-Value Observing with Combine
[iOS] KVO 란? (Key Value Observing)
Introduction to Key-Value Observing Programming Guide
'Swift' 카테고리의 다른 글
Swift: Result type (0) | 2023.10.01 |
---|---|
Swift: Mutating (0) | 2023.09.24 |
SwiftUI: String Subscript 접근 (0) | 2023.09.23 |
SwiftUI: Hashable, Equatable (0) | 2023.09.23 |
SwiftUI: Codable, Encodable, Decodable (0) | 2023.09.15 |