Featured image of post KVO(Key-value observing)

KVO(Key-value observing)

KVO (Key-value observing)

KeyValue의 쌍으로 옵저빙하는 것

Key-value observing is a Cocoa programming pattern you use to notify objects about changes to properties of other objects. It’s useful for communicating changes between logically separated parts of your app—such as between models and views. You can only use key-value observing with classes that inherit from NSObject.

다른 객체의 프로퍼티 변경사항을 객체에게 알려주는 코코아 프로그래밍 패턴
ModelView와 같이 논리적으로 분리된 파트사이에서 변경사항을 전달하는 데 유용하다.
objective-c에서 사용하던 방식이라고 생각하면 된다.
NSObject를 상속하는 클래스만 key-value observing을 사용할 수 있다.

Observig을 하기 위한 초기 설정(Annotate a Property for Key-Value Observing)

1
2
3
4
5
6
7
8
9
class Person {
    var name: String
    var age: Int

    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}

이름과 나이를 프로퍼티로 가지는 Person이라는 클라스가 있다고 했을 때, KVO를 적용하기 위해서는 무엇을 해야 할까?

  1. NSObject를 상속하는 클래스를 정의한다. 상속을 받아야 하기 때문에 class에서만 가능하다.
  2. observe 하려는 프로퍼티에 @objc attribute와 dynamic modifier를 붙여준다.
1
2
3
4
5
6
7
8
9
class Person: NSObject {
    var name: String
    @objc dynamic var age: Int

    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}

Obsever 정의(Define an Observer)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
var jae: Person = Person(name: "Jae", age: 20)

var gundy: NSKeyValueObservation?

gundy = jae.observe(
            \Person.age,
            options: [.old, .new]
        ) { object, change in
            print("\(object.name)의 나이는 \(change.oldValue!)에서 \(change.newValue!)으로 변경되었다.")
        }

jae.age = 21 // Jae의 나이는 20에서 21으로 변경되었다.
  1. jae라는 이름의 Person 인스턴스를 생성하고 20살로 설정하였다.
  2. gundy라는 이름의 변수(예제가 Person 타입이라 사람으로 지정했고 애플 사이트에서는 observation으로 되어 있다)에 jaeage 프로퍼티에 대한 옵저버 NSKeyValueObservation을 저장한다.
  3. 이제부터는 jaeage 값이 변경될 때마다, gundy에게 알려주게 된다.
    Observing이라는 네이밍이 다른 객체가 jae를 들여다보고 있는 것 같지만, 실제로는 jae 자신이 들여다보고 있다가 값이 변경되면 gundy에게 Optional 값으로 알려주는 형태이다.
    gundyjae가 보내준 노티를 받으면 { }안의 코드(여기서는 값이 바뀜을 출력)를 실행한다.

If you don’t need to know how a property has changed, omit the options parameter. Omitting the options parameter forgoes storing the new and old property values, which causes the oldValue and newValue properties to be nil.

애플 문서에서는 속성이 어떻게 변경되었는지 알 필요가 없는 경우 옵션 매개변수 options: [.old, .new]를 생략할 수 있고, 이 경우에는 oldValuenewValue 프로퍼티가 nil이 된다. ➡️ 그럼 KVO를 왜 쓰는거지❓

1
2
3
4
5
6
gundy = jae.observe(
            \Person.age
        ) { object, change in
            print("\(object.name)의 나이는 \(change.oldValue)에서 \(change.newValue)으로 변경되었다.")
        }
jae.age = 21 // Jae의 나이는 nil에서 nil으로 변경되었다.

KVO 장단점

장점

  • 두 객체 사이의 동기화가 용이하다.
  • 관찰된 프로퍼티의 oldValue와 newValue를 얻을 수 있다.
  • KeyPath를 가져오기 때문에(\Person.age) Nested object를 관찰할 수 있다.

단점

  • NSobject를 상속받는 객체에서만 사용이 가능하다.

  • 여러값을 관찰할 때는 복잡한 if문을 사용해야 한다.

Reference

Using Key-Value Observing in Swift
NSKeyValueObservingOptions
Zedd - Key-Value Observing(KVO) in Swift
Key-Value Coding(KVC) / KeyPath in Swift
leeari95 - KVO(Key-value observing)
Delegate, NOTIFICATION,KVO pros and cons

Licensed under CC BY-NC-SA 4.0