KBO? 아니 KVO!
KVO는 Key-value observing의 약자로서 이전에 얘기한 Delegate, Notification과 같이 변화에 대한 소통을 해주는 패턴 중 하나이다. KVO는 메서드나 액션을 통하지 않고 프로퍼티의 상태 변화에 반응하는 형태를 띄어, 보통은 객체와 객체 사이의 관계에서 많이 다루게 된다.
그렇다면 KVO는 어떻게 사용하는 걸까?
class Phone{
var number: String
init(number: String){
self.number = number
}
}
이와 같은 객체가 있다고 할 때, 우리는 저 number라는 변수의 변경될 때마다 이를 다른 객체에게 알리고 싶을 수가 있다. 이를 위해서는 먼저 NSObject를 상속해야 한다.
(KVO 패턴을 사용하기 위해서는 NSObject를 꼭 상속해야하며, 그러다보니 객체에서밖에 사용하지 못 한다)
class Phone: NSObject{
@objc dynamic var number: String
init(number: String){
self.number = number
}
}
위의 변경 예시와 같이 해당 객체에 NSObject를 상속시켜주고, 변화를 감지당할 수 있도록 해주고 싶은 프로퍼티에 @objc 속성과 dynamic 수정자를 추가해주면 된다.
......
var phoneNumber = Phone(number: "010-...")
phoneNumber.observe(\.number, options: [.old, .new]){ (object, change) in
print(change.oldValue, change.newValue)
}
위의 코드와 같이 KeyPath를 사용하여 해당 프로퍼티에 observer를 추가할 수 있으며, 이후에 프로퍼티의 값이 변경될 경우에는 observer의 change handler가 호출되면서 내부의 oldValue와 newValue에 접근할 수 있게 된다.
물론 options는 원하는 인자가 없으면 해당 매개변수를 사용하지 않고도 충분히 observer 등록이 가능하며, 이 경우에는 oldValue, newValue 모두 nil이 출력된다.
(즉, oldValue와 newValue 값은 optional)
options에는 old와 new 외에도 initial, prior도 있으니, 이후에 한 번 찾아서 확인해보는 것도 좋을 듯 하다.
쨘! 단 두 단계만으로도 당신의 프로퍼티에 Observer가!
앞으로 KVO 패턴을 사용하고 싶으면 위와 같은 단계를 따라서 진행하면 된다. 그렇다면 이쯤에서 KVO는 언제 사용하는 것이 좋고, 장단점은 무엇일까라는 궁금증이 들 수 있다.
앞서 말했듯이 KVO 패턴은 각 객체 간의 대화가 필요한 상황이나 어떠한 액션, 메서드와 관련 없이 프로퍼티의 변화에 주목해야 되는 경우에 사용하는 게 적절할 것이다.
장점으로는 접점이 없는 각 객체끼리 동기화가 가능해지며, 객체의 전체적인 구현을 변경하지 않으면서 내부 객체의 상태 변화에 대응 가능하다는 점이다. 또한 관찰 중인 프로퍼티의 변경 값뿐만 아니라 이전 값도 알 수 있고 KeyPath를 사용하기 때문에 중첩 프로퍼티도 관찰할 수 있다.
이와 반대로 단점은 NSObject를 무조건 상속해야하기 때문에 Objective-C와 깊게 연관될 수 밖에 없고 어떤 상황에서도 Class를 사용할 수 밖에 없게 된다.
어떤 패턴이든 장점과 단점 모두 가지고 있으니, 적절한 순간에 잘 쓰는 것이 중요하다.