2013년 9월 27일 금요일

[Cocoa] 코코아 바인딩 사용 시 데이터가 UI에 표시되지 않는 경우

OS X 용 앱의 UI를 개발 할 때 유용한 기능이 바로 코코아바인딩이다. 이 기능은 코드 레벨의 오브젝트(변수)와 UI 사이를 이어주어서 별 다른 코드 없이도 데이터를 UI에 렌더링 할 수 있게 해 준다.

그런데 바인딩을 제대로 했음에도 데이터가 표시되지 않거나 등의 문제를 겪을 수도 있다.

삽질의 발단은 인터페이스 빌더를 이용해 바인딩 한 NSMutableArray 객체를 코드 레벨에서 addObject를 이용해 초기화 시킨데서 발생했다. 초기화 한 array에는 데이터가 잔뜩 들어가 있는데 실제로 화면에는 표시되지 않는 것이다. 심지어 아무런 오류도 발생하지 않으니 뭐가 문제인지 파악하기가 힘들었다.

이런 문제는 바인딩 컨트롤러가 데이터가 변경되는 것을 파악하지 못 해서 발생한다.
코코아바인딩 시 NSMutableArray 오브젝트에 addObject나 removeObject 등을 이용해 데이터를 변조시키는 방법은 충분하지 않다. 바인딩 된 오브젝트는 아래 메서드들을 이용하자.
- (NSMutableArray *)mutableArrayValueForKey:(NSString *)key
- (NSMutableArray *)mutableArrayValueForKeyPath:(NSString *)keyPath
- (NSMutableSet *)mutableSetValueForKey:(NSString *)key
- (NSMutableSet *)mutableSetValueForKeyPath:(NSString *)keyPath
이 내용을 기초로 문제를 해결하려면 아래 중 한 가지 방법을 이용 할 수 있다:
  1. 바인딩 호환 객체를 가져와서 변조한다.
  2. 데이터가 변경된다는 것을 알려주고 변조한다.
  3. Mutation Method를 이용하지 않는다.
각 번호에 해당하는 자세한 내용은 아래에 이어진다.

1. 바인딩 호환 객체 가져오기

위에서 언급된 메서드를 이용하면 된다. 에를 들자면 이렇다.
NSMutableArray *array = [self mutableArrayValueForKey:@"bindingArray"];
[array addObject:someObj1];
...
이 코드는 위의 인용문에서 설명한 대로 self.bindingArray에 직접 addObject를 하지 않고 우회적으로 즉 바인딩 컨트롤러와 호환되는 객체를 엑세스 하는 방법이다.

2. 데이터가 변경되는 것을 알려주기

willChangeValueForKey 와 didChangeValueForKey 메서드를 이용해서 직접 객체를 엑세스 한다는 것을 알려주는 방법도 있다.
[self.willChangeValueForKey:@"bindingArray"];

[self.bindingArray addObject:someObj1];
...

[self.didChangeValueForKey:@"bindingArray"];
위와는 self.bindingArray를 직접 엑세스 하지만 수정이 끝난 후 바인딩 컨트롤러가 데이터가 수정되었음을 알 수 있게 한다. 다만 짝을 이루는 두 줄이 추가되어야 하니 만약 실수로 하나를 빠뜨리면 버그로 이어지게 된다. 주의하자.

3. 원본 데이터를 변조시키지 않기

굉장히 무식한(-_-) 방법이다. 효율도 좋지 않다. 하지만 어떻게 보면 가장 간단한 방법이다. 특히 초기화 시 딱 한번 실행되면 될 만한 것이라면 효율이 그렇게 나빠지는 것도 아니다.

굉장히 간단하게도, 별도의 컬렉션을 만들어서 이 컬렉션의 데이터를 수정 한 후 이 객체를 이용해 바인딩이 걸린 객체를 초기화 시키는 것이다. 예를 들어 NSMutableArray를 이용한다면
NSMutableArray *tmpArray = [[NSMutableArray alloc] init];
[tmpArray addObject:someObj1];
...
self.bindingArray = [NSMutableArray arrayWithArray:tmpArray];
이런 방식이다. self.bindingArray는 인터페이스 빌더를 이용해 바인딩 해 둔 멤버(프로퍼티)이다. 이렇게 하면 KVC(Key-Value Coding)를 신경 쓸 필요가 없어진다.

물론 효율을 신경써야 한다는 점은 이 방식의 가장 큰 단점이다.

관련링크) Troubleshooting Cocoa Bindings

댓글 없음 :