KVO(Key-Value-Observiing)란?
- KVO는 A객체에서 A의 변경사항을 B객체에게 알리기 위해 사용하는 코코아 프로그래밍 패턴이다.
- KVO를 사용하면 다른 개체의 특정 속성이 변경될 때 알림을 받도록 객체를 등록할 수 있다.
- 프로퍼티 옵저버인 willSet과 didSet이랑 유사하지만 외부에 관찰자를 추가하는것이 다르다.
- 또한 Objective-C 런타임에 의존하기 때문에 순수한 Swift에서는 그리 좋지 않다고한다...?
- 따라서 NSObject를 상속받는 클래스로 정의해주어야 하며, 각각의 프로퍼티에는 @objc dynamic 이라는 표시를 해야한다.
- RxSwift와 유사한 느낌이다?
Observing을 위한 Setup
class Address {
var town: String
init(town: String) {
self.town = town
}
}
town의 변경을 다른 객체에게 알리고 싶을 경우 해야하는 작업이 2가지 있다.
1. NSObject 상속: NSObject를 상속한 클래스에서만 KVO를 사용할 수 있다. (class 에서만 사용가능하다)
2. observe하려는 프로퍼티에 @objc 어트리뷰트와 dynamic modifier를 추가해야한다.
class Address: NSObject {
@objc dynamic var town: String
init(town: String) {
self.town = town
}
}
Observer 정의
observe 하려는 프로퍼티가 변경되는지 지켜보려면 observer가 필요하다.
var address = Address(town: "대전광역시")
// \. <-- KeyPath 객체의 속성을 참조하는데 사용되는 경로표현식
// observe내부 구문이 옵저버가 된다.
address.observe(\.town, options: [.old, .new]) { object, change in
print(change.oldValue, change.newValue)
}
address.town = "서울특별시"
// Optional("대전광역시") Optional("서울특별시")
1. town의 값을 "서울특별시"로 바꿈
2. 프로퍼티에 변경사항이 생기면
3. observer의 change handler가 호출되며
4. handler 내에서 oldValue와 newValue를 가져올 수 있다.
5. 변경 내용은 두번쨰로 전달되는 change로 전달된다.
그래서
Optional("대전광역시") Optional("서울특별시")
가 출력된다.
option에는 [.old, .new] 가 추가되어 있는데 변경 내용이 필요없다면 option을 주지 않으면 된다.
option[
- .old: 변경 전의 값
- .new: 변경 후의 값
- .initial: 초기화 시에도 observer가 불리게 할건지 라는 뜻!! 초기화시에 호출되게되면 oldValue는 nil이고 newValue는 초기화된 값이 전달된다.
- .prior: 이전의 상태와 지금의 상태를 다주는 옵션?
object에는 현재 address의 town값이 들어간다.
var address = Address(town: "대전광역시")
// \. <-- KeyPath 객체의 속성을 참조하는데 사용되는 경로표현식
address.observe(\.town, options: [.old, .new]) { object, change in
print(object.town)
}
address.town = "서울특별시"
address.town = "강원도"
// 서울특별시
// 강원도
궁금한점?
1. 성능상의 단점이 생긴다?
struct의 경우 프로퍼티 옵저버를 사용하면 Static dispatch를 사용하게 되어 성능상 이점이 있다.
class인 경우 class는 기본적으로 dynamic dispatch를 사용하는데 dynamic을 붙힘으로써 무조건 dinamic dispatch를 사용하게 되는가?
하지만 NSObject를 상속하면 Objective-C 런타임에 의존하게되고, Objective-C는 Message Dispatch를 사용하게되는데 클래스 자체가 Message Dispatch를 사용하게된다면 Address클래스는 Dynamic인가 Message인가 모르겠다.