-
[iOS] KVO 패턴iOS 2022. 6. 12. 15:14
KVO 패턴이란? : 한 객체의 프로퍼티가 변했음을 다른 객체에게 알리는 Cocoa 프로그래밍 패턴. 관찰하고자 하는 프로퍼티의 key path를 사용해 관찰할 수 있다.
KVO
KVO는 Key-Value Observing의 약자다. Key-Value observing은 한 객체에게 다른 객체의 프로퍼티가 변했음을 알리는 Cocoa 프로그래밍 패턴이다.
앱 내의 논리적인 부분들(model, view 등)이 변화 일어난 것을 서로 알리는데 유용하다.
Key-value observing은
NSObject
을 상속받은 클래스에서만 사용할 수 있다.NSObject?
NSObject는 대부분의 Objective-C 클래스 계층의 root 클래스다. NSObject 클래스를 상속받은 자식 클래스들은 런타임 시스템의 기본 인터페이스와 Objective-C 객체로서 동작할 수 있는 능력을 상속받는다.KVO를 사용할 프로퍼티 표시하기
KVO는 어떤 객체의 프로퍼티가 변했음을 다른 객체에 알리는 프로그래밍 패턴이라고 했다. 이 프로퍼티가 변했음을 알기 위해서는 프로퍼티를 관찰해야 한다.
KVO로 관찰하고 싶은 프로퍼티를
@objc
attribute와dynamic
modifier를 함께 붙여서 표시한다.class MyObservableObject: NSObject { // 관찰할 프로퍼티 @objc dynamic var level = 1 func levelUp() { level += 1 } }
위 코드에서는
MyObservableObject
클래스를 정의했고, 이 클래스는level
이라는 관찰할 수 있는 프로퍼티를 가지고 있다.Observer 정의하기
위에서 변화가 일어나는지 관찰할 프로퍼티를 정했다. 이제 이 프로퍼티가 변했음을 알림받을 관찰자, observer가 필요하다.
observer 클래스의 인스턴스는 하나 이상의 프로퍼티에서 생긴 변화에 대한 정보를 관리한다. Observer를 생성할 때, 내가 관찰하고 싶은 프로퍼티를 나타내는 key path로
observe(_:options:changeHandler:)
메서드를 호출해서 관찰을 시작한다.class MyObserver: NSObject { @objc var observableObject: MyObservableObject var observation: NSKeyValueObservation? init(object: MyObservableObject) { self.observableObject = object super.init() // observe(_:options:changeHandler:)는 self.observe~ 로 호출하는 메서드라 이 전에 super.init()을 호출해야 한다. self.observation = observe( \.observableObject.level, options: [.old, .new], changeHandler: { object, change in print("level was : \(change.oldValue!), level is now : \(change.newValue!)") }) } }
위
MYObserver
클래스에서는 관찰할 객체observableObject
를 프로퍼티로 가지고 있다. 그리고observe(_:options:changeHandler:)
메서드에서 관찰할 객체의level
프로퍼티가 변할 때,
변하기 이전의 값과 변하고 난 값을 모두 변한 내용을 담는 딕셔너리에 담을 수 있게 설정했다.changeHandler
에서는change
의oldValue
와newValue
프로퍼티를 사용하고 있다.change
는 NSKeyValueObservedChange 타입으로,indexes
,isPrior
,kind
,newValue
,oldValue
와 같은 프로퍼티를 가지고 있어서 내가 관찰하는 프로퍼티가 어떻게 변했는지 확인할 수 있게 해준다.만약 프로퍼티가 어떻게 변했는지 알 필요가 없다면
observe(_:options:changeHandler:)
의options
파라미터를 빼도 된다. 이options
를 빼면 프로퍼티의 변하기 이전 값과 변하고 난 값을 저장하지 않게 되기 때문에change
의oldValue
와newValue
가nil
이 된다.Observer 클래스도 NSObject를 상속해야 한다는 것을 잊지 말자.
Observer와 관찰할 프로퍼티 연결하기
우리는 위에서
- 관찰할 프로퍼티를 설정하고
- 프로퍼티를 관찰하는 Observer 클래스를 생성했다.
따라서 우리가 구현한 observer 클래스의 이니셜라이저에 관찰할 객체를 전달해서 관찰할 프로퍼티와 observer를 연결하면 된다.
let levelObject = MyObservableObject() let observer = MyObserver(object: levelObject)
프로퍼티가 변했을 때
KVO를 사용하는 객체들(위에서는
LevelObject
)은 프로퍼티의 값이 변할 때 observer에 변화를 알린다.levelObject.levelUp() // 자동으로 observer의 change handler가 호출된다. // level was : 1, level is now : 2
KVO와 Struct, Enum
위에서 설정한 변화를 관찰할 수 있는 프로퍼티는 클래스(objective-C 타입)이어야 하기 때문에, 구조체, 열거형은 KVO로 관찰할 수 없다.
전체 코드
import Foundation class MyObservableObject: NSObject { // 관찰할 프로퍼티 @objc dynamic var level = 1 func levelUp() { level += 1 } } class MyObserver: NSObject { @objc var observableObject: MyObservableObject var observation: NSKeyValueObservation? init(object: MyObservableObject) { self.observableObject = object super.init() // observe(_:options:changeHandler:)는 self.observe~ 로 호출하는 메서드라 이 전에 super.init()을 호출해야 한다. self.observation = observe( \.observableObject.level, options: [.old, .new], changeHandler: { object, change in print("level was : \(change.oldValue!), level is now : \(change.newValue!)") }) } } let levelObject = MyObservableObject() let observer = MyObserver(object: levelObject) levelObject.levelUp() // 자동으로 observer의 change handler가 호출된다. // level was : 1, level is now : 2
연습용으로 날짜를 관찰해서 25일 때 직원들에게 월급을 주는 회사 코드를 KVO로 짜보았다.
- 참조
반응형'iOS' 카테고리의 다른 글
[WWDC22] Hello Swift Charts (0) 2022.06.14 [WWDC22] What's new in Xcode (0) 2022.06.13 [WWDC22] What's new in Swift (0) 2022.06.13 [iOS] UIStackView와 AutoLayout, Dynamic height (0) 2022.05.27 [iOS] Roadmap (0) 2022.05.03