[iOS/OSX] 코어애니메이션 기본 개념

코어 애니메이션의 레이어

레이어 객체는 3차원 공간에 구성된 2차원 평면으로, 코어 애니메이션의 핵심이 되는 개념이다. 뷰와 비슷하게 레이어는 2차원 면의 기하학적 좌표정보, 콘텐츠, 시각적 속성등을 관리하게 된다. 하지만 뷰와는 달리 레이어는 그 스스로의 외양에 대해서는 정의하지 않는다. 레이어는 단지 비트맵을 둘러싸고 있는 상태 정보만을 관리한다. 이 비트맵은 뷰의 그려진 결과물이거나 지정한 비트맵 파일의 내용일 수 있다. 따라서 앱에서 사용하는 메인 레이어는 일종의 데이터 모델로 취급할 수 있으며 이러한 점은 애니메이션에 영향을 주는 것이므로 기억하고 넘어가야 한다.

레이어 기반 드로잉 모델

대부분의 레이어는 앱 내에서 실제 드로잉 동작을 하지는 않는다. 대신 레이어는 앱의 컨텐츠를 캡쳐하여 비트맵으로 캐시하는데 이는 종종 Backing Store로 표현된다. 레이어의 속성을 변경하는 것은 결국 레이어 객체의 상태 정보를 변경하는 것이다. 어떤 변경이 애니메이션을 유발하게 되면 코어 애니메이션은 레이어의 비트맵과 상태정보를 그래픽 하드웨어로 전달하게 되고, 새로운 정보(혹은 상태)로 렌더링 된다. 코어 애니메이션은 이처럼 하드웨어를 통해 비트맵을 처리하기 때문에 소프트웨어적인 변경보다 훨씬 빠를 수 있다.

레이어 기반 드로잉은 정적인 비트맵을 사용하기 때문에 전통적인 뷰 기반 드로잉 기술과 큰 차이점을 가진다. 뷰 기반의 드로잉 기법에서 뷰 자신에 가해진 변경은 drawRect:를 호출하여 컨텐츠를 그리게 된다. 하지만 이 동작은 CPU를 메인스레드에서 사용하기 때문에 상당히 비싼 작업이 된다. 코어 애니메이션은 비슷한 효과를 내기 위해 캐시된 비트맵을 하드웨어에서 처리하기 때문에 이러한 비용 부담을 줄이게 된다.

코어 애니메이션은 가능한한 많은 캐시 컨텐츠를 사용하지만, 앱은 반드시 초기 컨텐츠와 업데이트된 컨텐츠를 수시로 제공해야 한다. 레이어 객체에 컨텐츠를 제공하는 방법에 대해서는 뒤에서 다시 살펴보도록 하겠다.

레이어 기반 애니메이션

레이어 객체의 데이터와 상태정보는 레이어의 컨텐츠가 화면에 표시되는 시각적인 표현과 분리되어 있다. 이러한 구분은 코어 애니메이션이 기존 상태값에서 새로운 상태값으로 전환되는 애니메이션을 생성하는 방법을 마련한다. 예를 들어 레이어의 위치 정보를 바꾸는 것은 코어 애니메이션으로 하여금 레이어를 현재 위치에서 새로운 위치로 이동하도록 한다. 또한 다른 속성에 대한 변경은 해당 속성에 대한 애니메이션이 일어나도록 만든다. 이러한 애니메이션이 가능한 레이어의 속성 정보도 뒤에서 다시 소개하도록 하겠다.

애니메이션이 실행되는 중간에는 코어 애니메이션이 프레임별 드로잉작업을 처리해준다. 프로그래머는 초기 값과 종료값에 대해서만 지정하면 나머지는 코어 애니메이션이 알아서 처리한다. 물론 타이밍 함수와 같은 부가 정보도 설정할 수 있는데, 적절한 기본값이 이미 설정되어 있어서 그 값을 그대로 써도 대부분의 경우 괜찮은 효과를 볼 수 있다.

레이어 객체와 개별적인 기하 좌표계

레이어가 하는 일 중 한는 시각적인 좌표 정보를 다루는 것이다. 시각적 좌표정보에는 컨텐츠의 경계(bounds 속성), 위치와 크기(프레임 속성), 레이어가 회전할 것인지, 크기가 변할 것인지, 다른 어떤 방식으로 변형될 것인지등에 대한 정보를 포함한다. 뷰와 같이 레이어도 framebounds 속성을 가지고 있다. 레이어는 그외에도 뷰에 없는 다른 속성들을 가지고 있는데, 앵커포인트는 그 예이다. 앵커포인트는 변경이 일어나는 위치에 대한 정보를 담는다.

앵커포인트는 단위 좌표 공간에 의한 레이어상의 위치이다. 디폴트로 (0.5, 0,5)의 값을 갖는데 이는 레이어 사각형의 정중앙을 가리킨다.

레이어의 회전은 이 앵커포인트를 중심으로 일어나는데, 만약 왼쪽 위 꼭지점을 중심으로 레이어를 회전시키고자 한다면 앵커 포인트의 위치를 (0.0, 0.0)으로 변경 (OSX라면 (0.0, 1.0))해야 할 것이다.

또한 레이어는 기본적으로 3D공간에서 변형된다. 레이어 변형에 대한 함수 레퍼런스는 코어 애니메이션 함수 레퍼런스를 참고하자.

뷰와 레이어간의 관계

레이어는 뷰를 대체할 수 없다. 즉 레이어 객체들만으로는 시각적 UI를 만들 수 없다는 말이다. 레이어는 단지 뷰에 대해 인프라스트럭쳐를 제공할 뿐이다. 특히 레이어는 드로잉 작업을 효율적으로 만들고 뷰의 컨텐츠의 변경을 높은 프레임률로 애니메이트하는 기능을 제공한다. 그러나 레이어가 하지 못하는 것도 많다. 레이어는 이벤트를 다룰 수 없고, 컨텐츠를 그리지도 못하며, 응답체인과 연결되지 않는 등 한계가 명확하다. 이러한 이유로 이러한 상호작용을 다루기 위해서는 뷰를 사용해야 한다.

iOS에서는 모든 뷰가 레이어 객체를 가지고 있다. OSX는 어떤 뷰가 레이어를 가질지 개발자가 정의해야 한다. OSX 10.8이상에서부터는 모든 뷰가 레이어를 갖는게 맞는 것 같다. 그러나 이는 오버헤드를 늘리게 되므로 그렇게 할 필요도 없고 그렇게 해서도 안된다. 따라서 성능 테스트를 통해 적절한 타협점을 찾는 것이 필요하다.

뷰에 대해 레이어를 활성화시키면 layer-backed view를 생성했다고 말할 수 있다. 이 레이어 기반 뷰에서 시스템이 뷰를 위한 레이어를 만들고 뷰와 레이어를 동기화하게 된다. iOS에서는 모든 뷰가 이러한 레이어 기반 뷰이고, OSX에서도 대다수의 뷰가 이러한 레이어 기반 뷰이다. 추가로 OSX에는 layer-hosting view가 존재하는데 이 뷰는 해당 뷰의 레이어를 프로그래머가 따로 생성해서 부여할 수 있는 뷰이다. 레이어 호스팅 뷰에 대해서 앱킷 프레임워크는 자동적으로 뷰의 변경 사항에 대해서 응답하지 않는다.

레이어 기반 뷰에 대해서 레이어 자체보다는 뷰를 조작하는 것을 권장한다. 뷰가 레이어를 감싸는 얇은 래퍼(wrapper)이긴하지만, 이따금씩 레이어를 직접 조작하는 것이 원치 않은 결과를 유발할 수도 있다. 따라서 가능하면 레이어대신 뷰를 조작하는 쪽을 권장한다.

뷰와 연결되지 않는 독립 레이어를 만드는 것도 가능하다. 독립 레이어는 뷰와 별개로 생성되어, 뷰에 연계된 다른 레이어 객체의 서브 레이어가 될 수 있다. 이러한 패턴은 특정한 비트맵을 캐싱하여 다른 여러 뷰나 레이어에서 사용하는 경우 유리하다. (배경 타일링 등) 복사된 독립레이어는 동일한 비트맵을 참조하므로 메모리 사용량을 절약할 수 있다.

정리

  • 코어 애니메이션은 뷰의 위치, 투명도, 회전 및 기타 속성이 변경되는 것을 애니메이팅할 때 높은 품질의 애니메이션을 가능케하는 수단이다.
  • 부드러운 애니메이션을 위해 코어 애니메이션은 뷰의 내용을 비트맵으로 캐싱하여 하드웨어 레벨에서 처리하도록 한다.
  • 캐싱된 비트맵이 움직이거나 회전하는 것은 레이어 자체의 위치, 변형 정보에 의해 구현되는 것이다.
  • 이를 위해 뷰의 내용은 레이어에 의해 캐싱되고, 레이어는 캐시한 내용의 비트맵과 그외 기하학적 좌표 속성 정보를 사용해서 애니메이션을 구현한다. 이는 매 프레임마다 뷰의 내용을 그리는 것보다는 비용이 덜 드는 작업이므로 부드러운 애니메이션이 가능하다.