iOS
iOS) Key-Value Observing
kangwook
2022. 10. 11. 22:27
Notification Center를 공부하다가 접하게 된 개념이다.
정리가 필요할 것 같아서 여러 블로그들을 참고삼아 정리해보았다.
Key Value Observing이란 객체의 프로퍼티의 변경사항을 다른 객체에 알리기 위해 사용하는 Cocoa Programming Pattern
Model과 View와 같이 논리적으로 분리된 파트간의 변경사항을 전달하는데 유용(Notification Center와 유사)
NSObject를 상속한 클래스에서만 사용 가능
Observing을 위한 Setup
class Address {
var town: String
init(town: String) {
self.town = town
}
}
- 해당 클래스에 2가지 작업을 해줘야 함
- NSObject 상속 → 상속을 해야하므로 class에서만 사용 가능
- observe하려는 property에 @objc attribute와 dynamic modifier를 추가
변경된 모습
class Address: NSObject {
@objc dynamic var town: String
init(town: String) {
self.town = town
}
Observer 정의
var address = Address(town: "some_town")
address.observe(\.town, options: [.old, .new]) { (object, change) in
print(change.oldValue, change.newValue)
}
- keypath를 만들어서 프로퍼티 keypath에 observer를 추가할 수 있음
-
KeyPath Syntax
town의 값을 변경
- 프로퍼티에 변경이 생기면서 observer의 change handler가 호출됨
- handler내에서 oldValue와 newValue를 가져올 수 있음
var address = Address(town: "some_town")
address.observe(\.town, options: [.old, .new]) { (object, change) in
print(change.oldValue, change.newValue) // optional("some_town") Optional("any_town")
}
address.town = "any_town"
object?
var address = Address(town: "some_town")
address.observe(\.town, options: [.old, .new, .prior]) { (object, change) in
print(object.town)
// some_town
// any_town
}
address.town = "any_town"
- .prior 옵션은 현재값과 이전값을 모두 주는 옵션
- 따라서 object의 이전 값인 some_town을 출력하고 현재 값인 any_town을 출력
프로퍼티 옵저버(willSet, didSet)과의 차이점
- 프로퍼티 옵저버는 타입 정의 내부에 위치해야 하는 반면, KVO는 타입 정의 외부에서 observer를 추가할 때 사용
class Address: NSObject {
var town: String {
willSet { print(newValue) }
didSet { print(oldValue) }
}
init(town: String) {
self.town = town
}
}
KVO의 장점과 단점
장점
- 두 객체간의 동기화를 달성 가능(논리적으로 분리된 파트간의 변경사항을 전달)
- 객체의 구현을 변경하지 않고 내부 객체의 상태 변화에 대응할 수 있음(SDK 객체 등)
- 관찰된 프로퍼티의 이전값과 최신값을 제공
- KeyPath를 사용하여 프로퍼티를 관찰하므로 nested 프로퍼티도 관찰 가능
class Address: NSObject {
@objc ddynamic var town: String
init(town: String) {
self.town = town
}
}
class Person: NSObject {
@objc dynamic var address: Address
init(address: Address) {
self.address = address
}
}
단점
- NSObject를 상속해야함 → Objective-C 런타임에 의존하게 됨
참조