본문 바로가기

액션스크립트 3.0

AS3.0 핵심 개념 : Event Model


개요

 

액션스크립트 3.0 으로 넘어오면서 display object 구조 만큼 혁신적인 개선이라고 한다면, 단연 이벤트 모델이라고 할 수 있습니다. 기존 2.0 이하 버전에서는 단순한 callback 함수형태의 이벤트를 사용했습니다. 물론 사용하기엔 편했지만, 정밀한 제어를 할 수 없기 때문에 복잡한 인터랙셕을 구현하기 위해서는 반복적인 이벤트 코드를 사용할 수 밖에 없는 구조 였었습니다. callback 함수란 미리 이벤트 핸들러를 등록해놓고, 해당 이벤트가 호출됐을 때 리스너에게 이벤트를 전달해주는 개념을 강조하는 의미입니다. 3.0에서는 EventListener라는 조금 어려운 용어를 쓰고 있습니다. EventListener라는 개념에선 이벤트 우선 순위와 이벤트 흐름을 제어 할 수 있습니다. 3.0에서 Event Model의 어떤점들이 개선됐는지 알아보겠습니다.

 

더 강력하게 설계된 EventDispatcher 클래스와 Event 클래스의 도입.

 

EventDispatcher 클래스

 

EventDispatcher 클래스는 2.0에서도 본적 있죠?  2.0에서 사용하는 EventDispatcher는 리스너를 사용할 때 두개의 인자만 받습니다. 이벤트 타입과 이벤트 핸들러 입니다. 그러나 3.0에서는 EventListener를 사용할 때 다섯개의 인자를 받으므로써 훨씬 더 섬세한 제어를 할 수 있도록 설계되었습니다. 그럼 다섯개의 어떤 인자를 받는지 클래스 구조로 살펴보겠습니다.

 

//EventDisplatcher 클래스 구조 ----------------------------------

 

package

{

     public class EventDispatcher extends Object implements IEventDispatcher

     {

          //내부구현

     }

}

 

위 구조를 간략히 설명하자면 모든 클래스는 최상위 클래스인 Object 클래스를 상속 받게 구현되어 있습니다. 그리고

IEventDispatcher로 구현상속 또는 인터페이스 상속을 하고 있네요. 인터페이스는 EventDispatcher클래스의 골격을 제공해주죠. 인터페이스의 클래스를 상속받은 클래스는 인터페이스가 가지고 있는 메서드를 구현해야하는 의무를 가지고 있기 때문에 인터페이스 구조를 보면 EventDispatcher 클래스의 내부 구성을 알 수 있겠네요. 그럼 인터페이스의 내부구조를 보도록 하겠습니다.

 

//IEventDisplatcher 인터페이스 구조 ----------------------------------

 

package

{

     public interface IEventDispatcher

     {

          function addEventListener( type: String,

                                                 listener: Function,

                                                 useCapture: Boolean = false,

                                                 priority: int = 0;

                                                 useWeakReference: Boolean = false ): void;

 

          function dispatchEvent( event: Event ): Boolean;

          function hasEventListener( type: String ): Boolean;

          function removeEventListener( type: String,

                                                     listener: Function,

                                                     useCapture: Boolean = false ): void;

          function willTrigger( type: String ): Boolean;

     }

}

 

위 인터페이스 구조를 보면 총 다섯개의 메서드가 정의되어 있습니다.

 

첫번째 우리가 봐야할 부분은 "addEventListener"부분이 되겠네요. 총 다섯개의 인자값을 받는다는걸 알 수 있습니다.

보통 사용할 때 앞에서 2~3개의 인자만 사용합니다.

 

인자 설명 

1. type : 이벤트 타입을 받습니다.

2. listener : 이벤트 핸들러가 등록됩니다.

3. useCapture : 이부분은 이벤트 진행 단계를 제어하는 옵션입니다. capture --> target --> bubbling

4. priority : 우선 순위를 결정합니다. 값이 클수록 우선 순위가 높습니다. 여러개의 이벤트 핸들러가 등록되어 있을 경우 우선 순위가 높을수록 먼저 호출되게 됩니다.

5. useWeakReference : 참조 카운트를 어떤 식으로 관리할지 여부를 지정합니다. false는 강한 참조 카운터 관리 기법을 도입하므로써 이벤트리스너로 사용되는 함수가 가비지 컬렉션 되지 않도록 강제화 합니다. 가비지 컬렉션은 메모리 관리 관련 용어입니다.

 

두번째 dispatchEvent 메서드인데 인자로 이벤트를 하나 받습니다. 이벤트를 발생시킬 때 주로 사용합니다. OOP를 구현하기위해 반드시 사용법을 익혀야할 메서드 이기도 합니다.

 

세번째 hasEventListener 는 이벤트 핸들러의 존재 여부를 확인하는 메서드 입니다.

네번째 removeEventListener 는 등록된 인벤트 핸들러를 삭제하는 메서드 입니다.

다섯째 willTrigger 는 이벤트 흐름을 테스트하기 위한 메서드로써 이벤트 데이터형만을 넣어서 특정 이벤트의 흐름을 조사합니다.

 

Event 클래스

 

크게 2가지 목적으로 개발된 클래스 입니다.

 

첫번째는 이벤트 흐름의 시작 입니다. 어떤 객체에서 이벤트가 발생했는지 알려줌으로써 이벤트 흐름을 시작합니다.

두번째는 이벤트 흐름을 제어할 목적입니다.

 

Event 클래스는 EventDispatcher 클래스의 dispatchEvent 메서드의 인자로 사용되는데,  이벤트 클래스를 이해하려면 먼저 Event 클래스와 EventDispatcher 클래스의 상관관계를 알아야 합니다. Event 클래스는 이벤트의 흐름을 어떻게 할지 최종적으로 dispatchEvent 메서드를 통해 EventDispatcher 클래스의 변수로 저장됩니다. 이렇게 저장된 Event 클래스는 EventDispatcher 클래스에서 이벤트 핸들러( addEventListener )를 하나씩 호출할 때 마다  Event 가 등록되 있다면 해당 Event 클래스 흐름을 발생하게 되고 이벤트 리스너를 통해 인자로 전달되게 됩니다. 실제 Event 클래스는 자신의 이벤트 흐름을 제어하는게 아니라 이벤트 흐름을 결정할 수 있는 변수만 가지고 있고, 해당 변수를 EventDispatcher 클래스에서 읽어서 이벤트의 흐름을 결정합니다.

 

//Event 클래스 구조 ----------------------------------

 

package

{

     public class Event extends Object

     {

          //프로퍼티 생략 ----

 

          public function Event( type: String, bubbling: Boolean = false, cancelable: Boolean = false )

          {

               //내부구현 생략

          }

          public function clone(): Event { }

          public function formatToString( className: String, ...arguments ): String { }

          public function isDefaultPrevented(): Boolean { }

          public function preventDefault(): void {  }

          public function stopimmediatePropagation(): void { }

          public function stopPropagation(): void { }

          public function toString(): String { }

     }

}

 

위 Event 클래스 구조를 보면 총 8개의 메서드가 정의 되어 있습니다.

 

첫번째 Event 클래스는 초기 생성시 3개의 인자를 받습니다.

 

1. type : 이벤트 데이터 형입니다. addEventListener 에 사용된 이벤트 데이터 형과 동일합니다.

2. bubbles : Bubbling 단계 이벤트가 발생할지 여부를 결정합니다.

3. cancelable : 이벤트를 취소할 수 있는지 여부입니다. preventDefault 메서드와 연관된 값입니다. true일 때 preventDefault 기능이 작동합니다. 해당 이벤트를 취소할 뿐 이벤트 흐름을 중지시키는것 과는 별개라는걸 정확히 구분해야 합니다.

 

두번째 clone 이벤트리스너로 넘어온 이벤트 객체를 복사하는 메서드 입니다.

세번째 isDefaultPrevented 는 preventDefault 메서드가 호출됐는지 확인하는 메서드 입니다.

네번째 preventDefault 이벤트를 취소하는 메서드 입니다.

다섯째 stopimmediatePropagation는 즉시 이벤트 흐름을 종료 시키는 메서드 입니다.

여섯째 stopPropagation는 현재 노드에서만 이벤트 흐름을 종료합니다.

  

다음 다이어그램과 같이 표시 목록을 Stage가 맨 위에 있는 세로 계층 구조로 생각해 보면 각 단계의 이름을 쉽게 이해할 수 있습니다. 아래 도표는 마우스클릭 시 이벤트 흐름을 표현한 그림입니다.

 

 

 

지금 까지 액션스크립트 3.0 에서 사용하는 이벤트 체계에 대해서 알아봤습니다.

 

2.0으로 작업하던 유저들이 처음 3.0을 하면서 "왜케 복잡해졌어ㅜㅜ"라고들 말합니다. 저 또한 처음 접하고나서 이렇게 '복잡한걸 해야하나' 라는 의구심이 들었습니다. 물론 이전 버전보다 스크립트 표현구성은 훨씬 복잡해졌습니다. 하지만 그만큼에 혜택도 있습니다. 더욱 섬세한 컨트롤을 하므로써 Copy & Paste 에 익숙해져 있는 코딩습관을 탈피할 수 있고, 효율적인 알고리즘을 만들어 갈 수 있습니다. 또한 유지보수에도 굉장히 우수합니다. 많은 3.0컨텐츠를 만들고 3.0 Event Model에 익숙해지다 보면 그 강력함을 다시 한번 느낄 수 있을 겁니다.