2014년 2월 27일 목요일

[Objective-C] 변수의 값이 변하는 것을 추적하는 방법

iOS에선 UIView의 크기가 변하면 자동으로 서브뷰(Subviews)도 그와 함께 리사이즈 되도록 하는 기능이 존재한다. 하지만 subview가 바뀌었을 때 그 상위의 UIView의 크기가 따라 바뀌는 등의 기능은 제공하지 않는다. 따라서 코드레벨로 좀 수동으로 구현하는 것을 먼저 생각하게 될 것이다.

이번 포스팅은 위 예제상황에서 좀 더 편한 코딩을 하기 위해 '변수 값의 변화를 추적하는 것'에 대한 글이다. (정확히는 UIView와는 직접적인 관계가 없고 Objective-C 의 Key-Value Coding 과 관련된 내용이다)

[참고] 이 글은 옛날 글입니다. 새 글은 'KVO (Key-Value Observing) 소개' 글을 참고 바랍니다.

Objective-C 의 NSObject 에는 addObserver:forKeyPath:options:context 라는 메소드가 존재한다. 이 메소드는 특정 keyPath의 변화를 감지하기 위한 용도이다.

예제코드는 내용이 길어질 것 같아 몇 가지 상황을 가정하고 필요한 코드만 나열한다.

UIView 에서 파생된 특정 클래스는 sub-view의 변화에 따라 자신도 크기가 동적으로 변해야 한다. 여기서 sub-view는 self.someView 라는 프로퍼티에 할당되어 있다. 이 상황에서 self.someView.frame 의 변화를 감지하려면 아래 코드를 이용해 Observer를 동록하면 된다.
[self addObserver:self
       forKeyPath:@"someView.frame"
          options:0
          context:NULL];
만약 변화가 감지되면 어떻게 될까? 변화가 감지되면 NSObject 에 정의된 observerValueForKeyPath:ofObject:change:context 라는 인터페이스가 호출된다. 따라서 이를 구현해 주면 된다.
- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context
if ([keyPath isEqualToString:@"someView.frame"]) {
    // someView.frame의 변화에 맞게 자신의 frame도 바꾼다
    self.view.frame = CGRectMake(...);
}
실제로 동작하는 코드가 아닌 예제라서 좀 빈약하지만 어쨌든 이런 식으로 변수의 변화를 추적하고 대응하는 것이 가능해진다.

Observer가 필요없어지면 observer를 지워주는 것도 잊어먹지 말자.
[self removeObserver:self forKeyPath:@"someView.frame"];
위 예제코드는 self의 멤버 프로퍼티를 따라가는 거라 큰 문제는 없겠지만 많은 상황에서 removeObserver를 하지 않으면 앱이 죽는 문제도 발생 할 수 있다.

[관련글] KVO (Key-Value Observing) 소개

댓글 없음 :