코코아 바인딩이란

코코아 바인딩

기능적인 측면에서 가장 단순하게 설명하면, 코코아 바인딩은 모델과 뷰 사이에 어떠한 글루코드 없이 값과 디스플레이되는 것을 동기화시키는 것이다. 즉 바인딩을 구성하면 값이 바뀔 대 별도의 처리 없이 자동으로 뷰가 업데이트되고, 뷰에서 변경이 일어나면 즉시 값이 변경되는 것을 코드 없이 구현한다는 것이다.

즉 작성/유지해야 하는 코드의 양을 최소화하면서 이러한 기능을 제공한다. 코코아 바인딩을 적용하기 위해서 기존 코드를 재작성할 필요도 없다.

모델-뷰-컨트롤러 패턴

코코아에서 가장 많이 쓰이는 패턴은 모델-뷰-컨트롤러이다. 코코아 앱은 모델, 뷰, 컨트롤러가 각각의 객체로 구성되고, 서로 다른 기능을 수행한다. MVC에 일단 적응하고 나면, 많은 것들이 재사용 가능하고, 또 확장될 수 있다. 다른 애플리케이션에서도 모델 객체나 뷰 객체를 재사용할 수 있다. 대부분의 경우 컨트롤러가 하는 일은 일종의 ‘글루코드’를 담는 것인데, 이는 모델 데이터의 변경을 뷰에 반영하거나, 거꾸로 뷰에서 사용자가 만든 변경사항을 모델 데이터에 반영하는 것이다. 보통 이런 코드들은 앱별로 독특하게 돌아가는데다가 쓰기가 지루하다. 코코아 바인딩은 이런 코드의 양을 획기적으로 줄일 수 있게 한다.

코코아 바인딩은 이런 글루코드의 대부분을 재사용 가능한 컨트롤러 객체로 대신한다.

에를 들어 슬라이더 하나와 텍스트 필드가 있는 창을 생각해보자. 슬라이더는 특정한 값 사이를 오갈 수 있고, 텍스트 필드는 그 값을 표현한다고 하자.

만약 뷰에서 슬라이더를 움직이면 컨트롤러는 -updateNumberFrom: 이라는 메시지를 받게 되고, 그로부터 슬라이더의 현재값을 읽어 모델이 되는 객체에 저장하고, 다시 텍스트 필드의 -setFloatValue:를 호출하여 그 값을 반영하게 된다.

슬라이더 예제

코코아 바인딩은 이러한 컨트롤러 객체를 작성하는 대신, 미리 만들어진 컨트롤러 객체(NSObjectController)를 이용해서, 두 객체의 값을 묶을 수 있다. 이를 통해서 두 UI 요소의 값은 항상 동기화된다. 바인딩을 추가해주면 반대로 텍스트 필드를 업데이트하면 슬라이더가 자동으로 변경되게 할 수 있다.

![코코아 바인딩]https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CocoaBindings/art/sliderbindings_2x.png)

코코아 바인딩은 타깃-액션 패턴을 쓰지 않는다. 슬라이더는 컨트롤러에게 아무런 메시지를 보내지 않는다. 대신에 슬라이더가 움직이면 이는 컨트롤러에게 컨텐츠의 숫자값이 변경되었음을 알리고, 그 변경된 값이 무엇인지 알려준다. 그러면 컨트롤러는 모델의 숫자값을 변경하고 다시 텍스트 필드로 그 값을 업데이트한다.

바인딩 옵션

바인딩은 몇 가지 옵션을 제공하는데, 값 변환(value transform), 플레이스홀더, 다른 파라미터가 그것이다.

값 변환은 말 그대로 값에 대해 변환 필터를 적용할 수 있게 한다. Foundation은 NSValueTransformer와 같은 변환 클래스와 미리 만들어진 몇 가지 서브 클래스를 제공해준다. 예를 들면 위 예제에서 슬라이더는 화씨 온도값을 사용하고, 텍스트 필드로는 섭씨 온도값을 출력한다고 할 때, 섭씨-화씨를 변환할 수 있는 변환기를 작성하여 추가하면 이 과정을 자동으로 처리해주게 된다.

MVC 패턴의 확장

기존 컨트롤러에 추가된 바인딩의 형태

코코아 바인딩 아키텍쳐는 종래의 커스텀 컨트롤러 하나가 UI를 관리하던 MVC를 확장한다. 코코아 바인딩은 NSController를 상속받는 몇 가지 재사용 가능한 컨트롤러 클래스를 제공하고, 바인딩 기반의 앱에서 이러한 컨트롤러가 UI의 일부를 관리할 수 있다. 또 이러한 기본 컨트롤러 클래스는 서브클래싱이 가능하기에 NSArrayController를 상속받아 정렬이나 페칭 기능을 커스터마이징할 수도 있을 것이다.

보통의 컨셉에서 컨트롤러는 데이터 모델에 바로 묶이는 것 같지만 실질적으로 데이터 모델은 다른 컨트롤러에 의해 종속되어 있고, 컨트롤러는 그 컨트롤러나, 그 컨트롤러의 키패스를 통해서 간접적으로 바인딩되어 있다고 보는 편이 옳다.

지원 기술

코코아 바인딩은 KVC와 KVO에 거의 전적으로 의존하고 있다. 이 둘은 결합되어 키-밸류 바인딩을 만들어낸다.

NSController의 유용성

바인딩은 기본적으로 KVC, KVO를 지원하는 거의 모든 두 객체 사이에 구성될 수 있다. 뷰는 모델 객체와 바인드 될 수 있다. 하지만 바인딩 기반의 앱은 개별 모델 객체들이나 모델 객체의 집합을 사용자 설정 시스템과 인터페이스하기 위해 컨트롤러 객체를 사용한다.

  • NSController 객체는 자신의 현재 선택값과 플레이스 홀더 값을 관리한다. 이는 뷰가 선택값이 없거나 복수 선택값을 가진 경우라도 적절한 값을 표시할 수 있게 해준다.
  • NSControllerNSEditor, NSEditorRegistration 프로토콜을 지원한다. NSEditorRegistration 프로토콜은 에디터(뷰)에게 처리되지 않은 변경 사항이 있음을 알려줄 수 있다. NSEditor 프로토콜은 이 변경사항을 무시하거나 저장할 수 있게 한다. 예를 들어 사용자가 텍스트 필드에 타이핑을 하고 다른 버튼을 누르면 컨트롤러는 버튼 액션이 일어나기 전에 입력값이 완료된 것인지를 확인받는 절차를 거치게 할 수 있다. 이러한 메소드들은 주로 컨트롤러에 의해서 다른 UI요소들로 보내지지만, 반대로 컨트롤러가 이를 받을 수도 있다. (저장을 시도하거나 종료를 시도할 때 확인 받기)

NSController 클래스

NSController는 추상클래스로 이 자식 클래스는 NSObjectController, NSUserDefaultController, NSArrayController, NSTreeController 등이 있다. NSObjectController는 단일 객체를 관리하며 위에서 언급된 기능들을 제공한다. NSUserDefaultController는 사용자 설정 저장 시스템과의 인터페이스를 제공한다.

NSArrayControllerNSTreeController는 모델 객체의 집합을 관리하며 현재 선택된 값을 추적한다. 이러한 집합 컨트롤러들은 새로운 객체를 추가하거나, 선택된 객체를 제거할 수도 있다. 집합 컨트롤러가 관리하는 객체들은 컨테이너가 인덱스 방식 액세스만 지원한다면(-objectAtIndex, -objectForKey) 처리가 가능하다.

무엇을 묶을 수 있나

거의 대부분의 앱킷 객체는 바인딩을 적용할 수 있다.

실제 예시

게임앱을 예로 들어보자. 사용자는 일련의 전사를 관리하는데, 각각의 전사는 3가지의 무기를 가지고 다닐 수 있으며, 이 중 어느 하나를 선택할 수 있다. 앱에서는 창 상단에 전사의 목록을 보여주고, 하단에는 그 전사가 선택한 무기를 보여줄 수 있다. 이는 아래 그림과 같은 UI로 표현된다고 가정한다.

1

전사는 Combatant 클래스의 객체로 표현되는데, 이 클래스에서 각각의 무기는 개별 인스턴스 변수로 정의되며, 각 변수값은 ‘인덱스 기반’으로 액세스가 가능하다고 가정한다. 따라서 전사 클래스는 배열 컨트롤러를 통해서 무기에 액세스할 수 있다.

2

바인딩의 구성 요소는 다음과 같다.

  1. 전사 이름을 선택하면 창의 제목은 전사의 이름으로 변경된다.
  2. 전사가 변경되면 하단의 선택된 무기 값도 해당 전사의 것으로 변경된다.
  3. 전사가 선택할 수 있는 무기 전체는 선택된 전사의 무기 전체가 된다.

바인딩 구성도는 다음과 같다.

3

  1. 두 개의 배열 컨트롤러가 필요하다. 하나는 전사의 배열 전체를 contentArray로 갖는 컨트롤러가 있다.
  2. 다른 하나의 배열 컨트롤러는 1의 컨트롤러에서 선택된 객체의 weapons 프로퍼티에 바인딩된다. 따라서 키패스는 "selection.weapons"가 된다.
  3. 창의 타이틀은 배열 컨트롤러 1의 선택된 전사 이름이다. 따라서 이 모델 키는 "selection.name"이 된다.
  4. 전사 선택 박스의 value 값은 1의 전사의 이름 목록이며, 따라서 arrangedObjects.name이 된다.
  5. 전사를 선택하면 배열 컨트롤러1의 selection이 해당 전사 객체를 가리키는 프록시가 된다.
  6. 무기 목록은 선택된 전사의 것을 가져온다. 선택된 전사의 무기 목록은 배열컨트롤러2가 1의 선택값에 바인딩되어 있으므로 배열 컨트롤러 2에 바인딩되며, "arragnedObjects"가 된다.
  7. 무기 중 현재 선택된 값은 배열 컨트롤러 1의 "selection.selectedWeapon" 키패스와 연결된다.

이 구성은 다음과 같은 점을 시사한다.

  • 하나의 앱에서 하나 이상의 오브젝트 컨트롤러가 사용될 수 있다.
  • 하나의 UI 요소에 대해서도 다른 요소값들이 별개의 컨트롤러와 바인딩될 수 있다.
  • 커스텀 모델 객체를 쓸 수 있다.