[iOS] Objective-C의 KVC와 KVO 이해하기
KVC(Key-Value Coding)와 KVO(Key-Value Observing)는 이름이 비슷하지만 역할은 다르다. KVC는 문자열 키로 객체의 값을 읽고 쓰는 방식이고, KVO는 KVC를 기반으로 속성의 변경을 관찰하는 방식이다.
KVC: 문자열 키로 속성에 접근하기
NSKeyValueCoding은 객체의 프로퍼티를 이름이나 키 경로로 간접 접근하는 메커니즘이다. NSObject가 기본 구현을 제공하므로 Cocoa 객체에서는 일반적으로 별도 구현 없이 사용할 수 있다.
@interface TestObject : NSObject
@property (nonatomic, copy) NSString *testValue;
@end
@implementation TestObject
@end
TestObject *object = [TestObject new];
[object setValue:@"hello" forKey:@"testValue"];
NSString *value = [object valueForKey:@"testValue"];
NSLog(@"%@", value); // hello
키 경로를 사용하면 중첩된 객체에도 접근할 수 있다.
NSString *city = [person valueForKeyPath:@"address.city"];
문자열 키는 컴파일러가 오타를 검사하지 못한다. 존재하지 않는 키를 사용하면 기본적으로 NSUndefinedKeyException이 발생하므로, 상수나 NSStringFromSelector()를 활용해 키를 한곳에서 관리하는 편이 안전하다.
KVO: 속성 변경 관찰하기
KVO는 다른 객체의 프로퍼티가 바뀌었을 때 알림을 받는 옵저버 패턴이다. 관찰 대상 프로퍼티가 KVO 호환 방식으로 변경되어야 하며, 일반적인 Objective-C 프로퍼티의 setter를 통한 변경은 자동으로 알림을 발생시킨다.
static void *TestValueContext = &TestValueContext;
[object addObserver:self
forKeyPath:@"testValue"
options:NSKeyValueObservingOptionOld |
NSKeyValueObservingOptionNew
context:TestValueContext];
변경 알림은 observeValueForKeyPath:ofObject:change:context:에서 처리한다.
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary<NSKeyValueChangeKey, id> *)change
context:(void *)context {
if (context == TestValueContext) {
id oldValue = change[NSKeyValueChangeOldKey];
id newValue = change[NSKeyValueChangeNewKey];
NSLog(@"testValue: %@ → %@", oldValue, newValue);
return;
}
[super observeValueForKeyPath:keyPath
ofObject:object
change:change
context:context];
}
관찰이 끝나면 등록한 객체와 키 경로를 정확히 맞춰 해제한다.
[object removeObserver:self
forKeyPath:@"testValue"
context:TestValueContext];
옵저버의 수명과 해제 시점을 명확히 관리하지 않으면 크래시가 발생할 수 있다. 직접 인스턴스 변수에 값을 대입해 setter를 우회하거나, KVO 알림을 수동으로 비활성화한 경우에는 자동 알림이 발생하지 않을 수 있다.
KVO와 NotificationCenter의 차이
- KVO: 특정 객체의 특정 프로퍼티 변경을 관찰할 때 적합하다.
- NotificationCenter: 여러 객체가 하나의 의미 있는 이벤트를 구독할 때 적합하다.
- Delegate/Closure: 일대일 통신이나 명시적인 흐름이 필요할 때 이해하기 쉽다.
KVO는 모델 객체의 상태 변화를 연결하는 데 유용하지만, 문자열 키와 객체 수명 관리 비용이 있다. 이벤트의 의미가 중요하다면 Notification이나 명시적인 콜백이 더 읽기 쉬울 수 있다.
댓글남기기