[AS3] EventDispatcher의 이해

Programming/ActionScript 3.0 2007. 7. 13. 13:09
자료를 찾다가 AS3의 이벤트 모델에 대해 쉽게 설명된 자료가 있어서 내용 추가 및 수정하였다. AS2의 컴포넌트에서 사용했던 EventDispatcher는 AS3에서 모든 표시 오브젝트에서 사용하고 있는 EventDispatcher의 표준이 되었다. AS2에서는 addListener도 사용했으나 AS3에서는 좀더 구체적으로 Event를 dispatch 할 수 있는 EventListener만을 사용하고 있다.

AS3 이벤트 모델 개요
AS3의 이벤트 처리는 AS2의 이벤트처리와 조금 다른 것을 볼 수 있다.

1. 이벤트는 “전파”한다
AS3의 표시 오브젝트 DisplayObject으로부터 발생한 이벤트를 그 이벤트를 받은 오브젝트 뿐만이 아니라 다른 오브젝트에서도 리슨 할 수 있다.

발생한 이벤트(클릭되었다 등)는 상자가 된 오브젝트를 부모로부터 자식에게 자식로부터 부모에게 이벤트가 전해져 가는 모델을 채택하고 있다. 이 개념은 이벤트의 전파(event propagation)라 불린다. 이벤트는 트리 구조 안을 이동하면서 각층(노드)에서 대응하는 리스너가 있을지를 검사하고, 있을 경우에는 그 리스너를 실행하게 된다.

예를 들어, 아래와 같이 상자 구조가 있다고 했을 때 DisplayObject (Sprite)를 생각해 보면, Sprite mc_01의 안에 mc_02 라는 Sprite이 있고 그 안에 mc_03라고 하는 Sprite이 있는 구조로 되어 있다. 여기서 mc_03를 클릭한다고 했을 때 AS2에서는 mc_03에 리스너를 등록할 필요가 있었지만 AS3에서는 mc_03 뿐만이 아니라 mc_02와 mc_01라는 Sprite에 설정한 리스너로 mc_03에서 이벤트를 취급할 수가 있다.

 
[상자 구조 샘플]

이것을 적절히 사용하면 이벤트 처리를 집중화시키는 것이 가능하다 .예를 들면 mc_02 ,mc_03에 공통의 이벤트 처리를 하고 싶은 경우라면 각각의 오브젝트에 이벤트 리스너를 등록할 필요가 없다.

2. 전파의 종류
전파는 아래와 같이 3단계로 분류된다.

1. 캡처-단계
2. 타켓-단계
3. 버블링-단계

이벤트의 전파는 원래 DOM (문서 오브젝트 모델)에 대한 이벤트 모델로서 브라우저에 도입된 것이다. (Netscape의 「이벤트 캡쳐링」모델,  Microsoft의 「이벤트 버블링」모델) W3C에 책정되고 있는 이벤트 모델이나 DOM에 대해서는 더 많은 정보가 필요해서 생략한다. 그러나 그 구현 방법은 ActionScript의 이벤트모델과 매우 유사하기 때문에 간단하게라도 알아 두는 편이 도움이 될 것 같다.

3.  캡쳐-단계
AS3에서 제일 초기에 실행되는 것은 이 캡쳐-단계다. 계층 구조의 오브젝트를 검사(리스너가 있는지를 조사)해 가면서 발생한 이벤트에 대응하는 리스너가 있으면 실행하게 된다. 캡쳐-단계에서의 이벤트는 루트로부터 이벤트가 발생한 타겟을 향해서 전파해 나간다.

위 샐플로 이야기하면 mc_03이라는 무비클립이 클릭되었을 경우 타겟은 mc_01 ,mc_02의 순서로 이벤트의 검사하게 된다. 타겟이 되는 mc_03의 이벤트 검사는 캡쳐-단계에서는 포함되지 않는다.

4.  타겟-단계
두번째로 이벤트의 검사를 하는 것은 타겟 단계이다. 이벤트가 발생한 타겟 자체의 이벤트 리스너를 실행한다. AS2의 관점에서 생각하면 이 타겟 단계만 실행된다고 할 수 있다. ‘

5.  버블링-단계
마지막에 이벤트의 검사를 하는 것은 버블링 단계다. 캡쳐-단계와는 반대로 타겟으로부터 루트를 향해서 전파 해 나간다.

위 샘플로 말하면 mc_03이 클릭되었을 경우 타겟은 mc_02 ,mc_01의 순서로 이벤트의 검사를 한다. 타겟이 되는 mc_03의 이벤트 검사는 버블링 단계에서도 포함되지 않는다.

6.  리스너는 중복 실행되지 않는다
여기서 생각해볼 것은 위에서 캡쳐단계와 버블링단계에서 처럼 리스너가 이중으로 실행된다고 생각할 수 있겠으나 그렇지는 않다. AS3의 캡쳐단계에서 리스너는 디폴트로 무효가 된다. 즉, 실질적으로 타겟으로부터 시작해 루트를 향해서 이벤트가 전파 해 나갈 뿐인 것이다. 물론, 캡쳐단계에서 리스너를 유효하게 할 수도 있지만 그럴 경우에는 버블링 단계에서 리스너가 무효가 된다.
양쪽 모두의 이벤트를 유효하게 할 수도 있다 이는 아래에서 이야기한다.


AS3 이벤트 관련의 클래스, 메소드에 대해
이벤트의 전파를 어떻게 제어하는 지와 관련된 클래스나 메소드에 대해 살펴보면 다음과 같다.

1.  addEventListener 메소드
AS3의 표시 오브젝트인 DisplayObject는 EventDispatcher를 상속하고 있다. 따라서 DisplayObject인 모든 군은 addEventListener 메소드를 사용할 수 있다. 여기서 AS3의 EventDispatcher.addEventListener 의 문장구조를 보면 다음과 같다.
addEventListener(
type:String,
listener:Function,
useCapture:Boolean = false,
priority:int = 0,
useWeakReference:Boolean = false
):void
먼저 기본이 되는 인수 type과 listener에 대해서는 기존 AS2의 EventDispatcher 와 다르지 않다. type 은 이벤트 타입(이벤트의 이름, “click” 등)이다. listener는 리스너 핸들러 함수다. 이벤트가 발생하여 리슨 되었을 때에 실행되는 함수다. 나머지의 인수는 옵션인데 설정하지 않는 경우는 디폴트 값이 적용된다.

useCapture는 캡쳐-단계에 리슨을 실시할지의 Boolean 값이다. 디폴트 값은 false다. useCapture를 true로 설정했을 경우 그 리스너는 캡쳐-단계에 이벤트를 리슨 하게 되지만 반대로 버블링 단계에서는 이벤트를 리슨 하지 않는다.

양쪽 모두 리슨 하는 경우는 useCapture의 값을 true / false로 하는 2개의 이벤트 리스너를 등록할 필요가 있다. 또, 레퍼런스에 의하면 캡쳐 단계에서 이벤트를 리슨 하게 되면 계산 처리의 부하가 커진다고 하니 특별한 이유가 없을 때에는 디폴트 값 false로 해 두는 것이 좋을 것이다.

priority는 우선도를 나타낸다. 수치가 큰 것일 수록 선행 처리된다. priority 값이 같은 경우에는 등록된 순서대로 처리된다. 부의 값도 이용할 수 있으므로, 디폴트값(0)을 기준으로 우선도를 설정할 수 있다. 다만, 우선도의 높은 처리가 완료되고 나서 낮은 처리가 다시 시작되는 것은 아니다..

useWeakReference는 리스너에 의한 참조가 약참조인지 어떤지를 나타내는 Boolean 값이다. 디폴트는 false이고 이는 강참조를 나타낸다. useWeakReference의 값을 true로 했을 경우에는 리스너의 가베지 콜렉터로부터 회피된다. 이에 대한 내용은 전에 작성한 포스트에서 확인할 수 있다.

2.  Event 클래스(오브젝트)
AS2의 EventDispatcher는 리스너에게 건네지는 이벤트 오브젝트와 type 프롭퍼티는 Object형태로 전달되었다. 하지만 AS3에서는 Event 클래스가 준비되어 있고 그것을 확장한 여러 가지 서브 클래스가 있다. 예를 들면 마우스 이벤트용의 MouseEvent 클래스나, 키보드 이벤트용의 KeyboardEvent 클래스 등이다.

KeyboardEvent 이벤트는 조작된 키의 키코드를 가지는 등 각각이 잘 정리되어 있다. Event 클래스를 확장하여 자작의 커스텀 클래스를 만들 수도 있다. 이는 예전 포스트에서 이미 내용을 기술해 놓았다.

3.  Event 클래스의 프롭퍼티
이벤트 오브젝트의 베이스가 되는 Event 클래스의 프롭퍼티를 보면 다음과 같다.

bubbles 프롭퍼티는 그 이벤트가 버블링 할지를 나타내는 Boolean 값이다. 디폴트는 false이고 그 경우 이벤트는 버블링 하지 않는다. MouseEvent 등은 true로 설정되어 있고 버블링 단계도 기능한다. 서브 클래스마다의 bublles 프롭퍼티는 레퍼런스를 참조해야 할 것 같다.

cancelable 프롭퍼티는 이벤트의 디폴트 동작을 캔슬할 수 있을지의 Boolean 값이다. 디폴트 동작의 캔슬에 대해서는 전 포스트에서 기술 한 적이 있다. isDefaultPrevented 프롭퍼티는 캔슬이 끝난 상태인지 어떤지를 보존하는 Boolean 값이 된다.

currentTarget / target 프롭퍼티는 각각 타겟의 참조다. target은 이벤트가 발생한 오브젝트의 참조다. currentTaget은 이벤트가 전파 하고 있을 때 이벤트가 어디에 있는지를 나타낸다. 즉, 오느곳의 오브젝트로 리스너를 검사하고 있는지를 나타내어 그 오브젝트의 참조를 돌려준다. target 프롭퍼티는 하나의 이벤트 오브젝트로 공통이지만 currentTaget 프롭퍼티는 전파 하는 과정에서 변해간다.

eventPhase 프롭퍼티는 이벤트가 어느 단계에 있는지를 나타내는 정수치를 가지고 있다.
1 - 캡쳐-단계
2 – 타겟-단계
3 – 버블링-단계

type 프롭퍼티는 이벤트 타입을 나타내는 String 값이다. 예를 들면 "click" 이나 "mouseOver" 등. addEventListener 의 type 값과 조합된다. 리스너는 이 값을 지정하여 이벤트를 리슨 한다.

4.  이벤트는 타겟 단계 밖에 동작하지 않아?
캡쳐-단계와 버블링 단계가 일어나는 것은 DisplayObject 오브젝트만이다. AS2 같이 표시 되어 있지 않은(표시 리스트에 없다) 오브젝트로부터도 이벤트는 dispatch 된다. 예를 들어 “로드가 완료했다”등이라고 하는 것과 같은 이벤트에 대해서도 dispatch 및 청취자는 같은 구조를 취한다. 이러한 이벤트는 많은 경우 전파 할 필요가 없고 이벤트는 타겟으로 직접 플로우 한다.

5.  이벤트의 전파를 정지한다
Event 클래스에는 stopPropagation / stopImmediatePropagation라고 하는 메소드가 있다. 이것들을 이용하면 이벤트의 전파를 도중 캔슬할 수도 있다. 즉, 리스너 안에서 건네 받는 이벤트 오브젝트를 이용하여 그 이벤트의 전파를 멈출 수 있다.

stopPropagation 메소드는 그 이벤트의 전파 자체는 정지하지만 현재의 노드(검사중의 오브젝트)의 리스너는 모두 처리한다.
stopImmediatePropagation 메소드는 전파도 정지하고 현재의 노드의 다른 리스너도 처리하지 않는다.

6.  이벤트의 디폴트의 동작을 캔슬한다
많은 이벤트에는 이벤트 발생시에 디폴트로 실행하는 동작이 있다. Event 오브젝트의 cancelable 프롭퍼티가 true의 경우에 한해서 Event.preventDefault 메소드를 이용하면 이러한 동작을 캔슬할 수 있다.

아래는 레퍼런스의 내용이다.

「예를 들어, 유저가 텍스트 필드에 문자를 입력했을 경우 디폴트 동작에서는 문자가 텍스트 필드에 표시됩니다. TextEvent.TEXT_INPUT 이벤트의 디폴트 동작은 캔슬하기 위해 preventDefault() 메소드를 사용해 문자를 표시하지 않게 할 수 있습니다.」

7.  이벤트의 dispatch
이벤트의 dispatch는 AS2의 EventDispatcher와 같이 dispatchEvent 메소드를 실행할 뿐이다. 다만, dispatchEvent에 건네주는 인수가 AS2에서는 Object이고 AS3는 Event 오브젝트라는 것이 다르다.
새로 Event 오브젝트를 만들고 dispatchEvent의 인수로 건네주게 된다.

Event오브젝트의 constructor는 다음과 같은 문장구조를 갖는다.
Event(event_type:String, bubbles:Boolean, cancelable:Boolean)
bubbles 와 cancelable은 옵션으로 생략 할 수 있다. 간단한 dispatchEvent는 아래와 같다.

my_obj.dispatchEvent(new Event(MouseEvent.CLICK));


    

설정

트랙백

댓글

[AS3] 이벤트 리스너와 garbage collection

Programming/ActionScript 3.0 2007. 7. 5. 04:35
필요 없는 오브젝트의 참조가 남아있으면 그 오브젝트가 사용하고 있는 메모리 영역을 사용할 수 없게 된다. 특히 복수가 참조하는 오브젝트에 대해서는 참조를 해제하는 것을 잊어버리게 되면 메모리의 낭비가 발생하므로 주의해야 한다.

이벤트 리스너를 등록하려면 이벤트의 타겟으로 되는 오브젝트와 이벤트 리스너를 가지는 오브젝트 사이에 참조를 할 수 있다. AS3에서는 아래와 같이 기술한다.

eventTarget.addEventLisener("eventType", eventHandler);

이 코드를 실행하면 eventTarget과 현재 스크립트가 포함된 this 사이에 참조가 만들어진다. 하지만 이것은 명시적인 참조의 추가가 아니기 때문에 참조의 삭제가 필요한 경우 간과할 수 있다.

아래는 이벤트 리스너 추가시에 참조의 취급 방법에 대한 내용이다.


참조의 방향
참조에는 방향성이 있다. 즉, 오브젝트간의 참조는 한 방향으로만 가능하다. 예를 들면 아래와 같은 코드가 있을 때,
var foo = new Foo();
foo.bar = this;
foo = null;
1행에서 만들어진 참조는 this -> new Foo() 방향으로 만들어진 참조이다. 2행에서 만들어진 참조는 1행과 반대로 new Foo() -> this 방향으로 만들어 진 참조다. 3행에서 1행의 참조를 삭제하게 되면 this -> new Foo()으로의 참조를 할 수 없다.

가비지컬렉터는 오브젝트 트리의 루트로부터 참조를 찾아 들어 간다. 우선 루트의 오브젝트를 찾아내고 다음에 그 오브젝트의 오브젝트를 찾아내는 동작을 반복하게 된다. 위 샘플을 실행했을 경우 this에 new Foo()로 만들어진 오브젝트를 찾아 낼 수 없다. 즉 2행째에 작성한 참조가 남아있다고 해도 3행을 실행하게 되면 메모리 문제는 해결될 수 있다.


오브젝트에 이벤트 리스너 추가
오브젝트에 이벤트 리스너를 추가할 경우에 참조 방향으로는 아래와 같다.
import flash.events.Event;
import flash.events.MouseEvent;
var foo = New Foo();
addChild(foo);
foo.addEventListener(MouseEvent.CLICK, clickHandler);

function clickHandler(evt:Event):void{
trace(this);
}
위 코드에서 foo 오브젝트를 작성하고 그 오브젝트에 clickHandler라는 이벤트 리스너를 등록하였다. clickHandler 메소드는 스크립트가 작성된 this 오브젝트의 메소드가 된다.

이러한 경우 foo 오브젝트의 참조를 삭제할 때 이벤트 리스너도 삭제하지 않으면 메모리에 잔존하는 문제의 원인이 될 수 있다. 아래와 같이 오브젝트로부터 this에 이벤트 리스너를 설정할 경우도 같다.
parent.addEventListener("click", clickHandler);
약한 참조의 이용
약한 참조는 참조가 존재하고 있어도 가비지콜렉터에 의해서 참조로서 보이지 않는 참조이다. 이는 매우 편리하게 사용할 수 있는데 이벤트 리스너에 의해 생성되는 참조가 모두 약한 참조라면 참조의 방향을 신경 쓰지 않고 등록한 리스너를 방치해 두어도 문제가 되지 않기 때문이다. 이벤트 리스너를 등록할 때 약한 참조를 사용할지를 지정할 수 있다. addEventListener()의 5번째 인수를 true로 적용하면 약한 참조를 사용할 수 있다.
addEventListener("eventType", listenerHandler, false, 0, true);
3번째와 4번째 인수는 false와 0 값을 지정해 두면 대체적으로 문제가 없기 때문에 위와 같은 형태로 5번째 인수를 false와 true로 적용하여 강한 참조와 약한 참조를 사용할 수 있다.

    

설정

트랙백

댓글

[AS3] 이벤트 청취자

Programming/ActionScript 3.0 2007. 6. 17. 03:30
이벤트 청취자란 특정한 이벤트에 응답하여 Flash Player에 의해 실행되는 함수이며 이벤트 핸들러라고도 불린다. 이벤트 청취자를 등록하려면 2개의 순서로 실행한다. 우선, 목적 이벤트에 응답하여 Flash Player에서 실행시키기 위한 함수 또는 클래스 메소드를 작성한다. 이것은 청취자 함수 또는 이벤트 핸들러 함수로 불리기도 한다. 그 다음에 addEventListener() 메소드를 사용하여 그 청취자 함수를 이벤트의 타겟 또는 해당하는 이벤트 플로우에 포함되는 임의의 표시 리스트 오브젝트에 등록하는 과정으로 진행한다.

청취자 함수의 작성
ActionScript 3.0의 이벤트 모델 가운데 청취자 함수의 작성에 관한 부분은 DOM 이벤트 모델에 준거하고 있지 않다. DOM 이벤트 모델에서는 이벤트 청취자와 청취자 함수가 명확하게 구별되고 있다. 이벤트 청취자는 EventListener 인터페이스를 implements한 클래스의 인스턴스를 의미하며 청취자 함수는 그 클래스가 갖춘 handleEvent() 메소드를 의미한다. DOM 이벤트 모델에 대해서는 청취자 함수 자체를 등록하는 것이 아니라 청취자 함수를 포함한 클래스 인스턴스를 등록하는 형식을 취한다.

ActionScript 3.0의 이벤트 모델은 이벤트 청취자와 청취자 함수와의 구별이 없다. ActionScript 3.0 에는 EventListener 인터페이스가 없고 청취자 함수는 클래스내 클래스외에 정의할 수도 있다. 또, 청취자 함수의 이름이 handleEvent() 일 필요는 없고 식별자로서 유효한 임의의 이름을 붙일 수 있다. ActionScript 3.0에서는 대체적으로 청취자 함수 자체의 이름을 등록하는 형식을 취하지만 그렇게 해야만 하는 것은 아니다.

클래스외에 정의한 청취자 함수
다음의 코드는 붉은 정방형의 셰이프를 표시하는 단순한 SWF 파일이다. 클래스내에 있는 clickHandler() 청취자 함수로 붉은 정방형에 대해 사용자의 마우스 클릭 이벤트를 받아들이고 있다.

package {
import flash.display.Sprite;

public class ClickExample extends Sprite {
public function ClickExample() {
var child:ChildSprite = new ChildSprite();
addChild(child);
}
}
}

import flash.display.Sprite;
import flash.events.MouseEvent;

class ChildSprite extends Sprite {
public function ChildSprite() {
graphics.beginFill(0xFF0000);
graphics.drawRect(0,0,100,100);
graphics.endFill();
addEventListener(MouseEvent.CLICK, clickHandler);
}
}

function clickHandler(event:MouseEvent):void {
trace("clickHandler detected an event of type: " + event.type);
trace("the this keyword refers to: " + this);
}
이 SWF 파일에서는 유저에 의해서 정방형이 클릭되면 Flash Player는 다음의 trace 출력을 생성한다.

clickHandler detected an event of type: click
the this keyword refers to: [object global]

이벤트 오브젝트가 clickHandler()에 파라미터로서 건네 받고 있다. 이것에 의해 청취자 함수 중에서 이벤트 오브젝트를 조사할 수 있다. 이 예에서는 이벤트 오브젝트의 type 프롭퍼티를 사용하여 이벤트가 "click" 이벤트인 것을 확인하고 있다.

이 예에서는 this 키워드의 값도 확인하고 있다. this는 글로벌 오브젝트를 참조하고 있다. 왜냐하면 청취자 함수를 커스텀 클래스나 오브젝트에 속하지 않는 외부에서 정의하고 있기 때문이다.

클래스 메소드로서 정의한 청취자 함수
다음의 예에서는 위에서 이야기 한 것과 같이 ClickExample 클래스를 정의하고 있지만 clickHandler() 함수를 ChildSprite 클래스의 메소드로서 정의하고 있는 점이 다르다.

package {
import flash.display.Sprite;

public class ClickExample extends Sprite {
public function ClickExample() {
var child:ChildSprite = new ChildSprite();
addChild(child);
}
}
}

import flash.display.Sprite;
import flash.events.MouseEvent;

class ChildSprite extends Sprite {
public function ChildSprite() {
graphics.beginFill(0xFF0000);
graphics.drawRect(0,0,100,100);
graphics.endFill();
addEventListener(MouseEvent.CLICK, clickHandler);
}
private function clickHandler(event:MouseEvent):void {
trace("clickHandler detected an event of type: " + event.type);
trace("the this keyword refers to: " + this);
}
}

이 SWF 파일로 유저에 의해서 붉은 정방형이 클릭되면 Flash Player는 다음의 trace 출력을 생성한다.

clickHandler detected an event of type: click
the this keyword refers to: [object ChildSprite]

this 키워드는 ChildSprite 인스턴스를 참조하고 있다. 이 점에 관해서는 동작이 변경되고 있어 ActionScript 2.0과는 다르다. ActionScript 2.0 의 컴퍼넌트에서는 UIEventDispatcher.addEventListener() 에 대해서 클래스 메소드를 지정했을 경우 청취자 메소드의 스코프는 메소드가 정의되고 있는 클래스가 아니라 이벤트를 브로드캐스트 한 컴퍼넌트에 근거해 정해지게 되어 있었다. 즉, 이 예와 같은 테크닉을 ActionScript 2.0에서 작성했다고하면 this 키워드는 ChildSprite 인스턴스가 아니라 이벤트를 브로드캐스트 한 컴퍼넌트를 참조하게 된다.

예전의 ActionScript에서는 청취자 메소드로부터 그 메소드가 있는 클래스 내의 다른 메소드나 프롭퍼티에 액세스 할 수 없기 때문에 경우에 따라서는 매우 큰 문제가 생기고 있었다. 이것을 회피하기 위해서 ActionScript 2.0 에는 mx.util.Delegate 클래스를 사용해서 청취자 메소드의 스코프를 변경할 수 있는 방법이 준비되어 있었다. 하지만 ActionScript 3.0부터는 addEventListener() 의 호출시에 bound methods가 작성되기 위해서 이 해결방법은 불필요한 것이 되었다. 결과적으로 this 키워드의 참조처는 ChildSprite 인스턴스인 child가 되어 ChildSprite 클래스내의 다른 메소드나 프롭퍼티에 액세스 할 수 있게 되었다.

바람직하지 않은 이벤트 청취자 등록의 방법
제 3 의 테크닉으로서 범용 오브젝트를 작성해서 그 오브젝트의 프롭퍼티에 의해서 동적으로 청취자 함수를 할당하는 방법이 있지만 이것을 사용하는 것은 추천할 수 없다. 이 방법을 설명하는 것은 ActionScript 2.0에서 일반적으로 사용되고 있었던 바람직하지 않은 방법이라는 이유 때문이다. ActionScript 3.0에서는 사용하지 않는 것이 좋다. 이 테크닉에서는 this 키워드의 참조처가 청취자 오브젝트가 아니라 글로벌 오브젝트가 되기 때문에 바람직하지는 않다.

다음의 예에서는 위에서 작성한 것과 같이 ClickExample 클래스를 정의하고 있지만 청취자 함수를 myListenerObj라고 하는 범용 오브젝트의 일부로서 정의하고 있는 점이 다르다.

package {
import flash.display.Sprite;

public class ClickExample extends Sprite {
public function ClickExample() {
var child:ChildSprite = new ChildSprite();
addChild(child);
}
}
}

import flash.display.Sprite;
import flash.events.MouseEvent;

class ChildSprite extends Sprite {
public function ChildSprite() {
graphics.beginFill(0xFF0000);
graphics.drawRect(0,0,100,100);
graphics.endFill();
addEventListener(MouseEvent.CLICK, myListenerObj.clickHandler);
}
}

var myListenerObj:Object = new Object();
myListenerObj.clickHandler = function (event:MouseEvent):void {
trace("clickHandler detected an event of type: " + event.type);
trace("the this keyword refers to: " + this);
}
trace의 결과는 다음과 같다.

clickHandler detected an event of type: click
the this keyword refers to: [object global]

this 의 참조처는 myListenerObj 인 것 같이 보여 trace 출력도 [object Object]가 되어 있지만 실제의 참조처는 글로벌 오브젝트다. 동적인 프롭퍼티명을 addEventListener() 의 파라미터로서 지정했을 경우 Flash Player는 bound methods를 작성할 수가 없다. 왜냐하면 이 경우에 listener 파라미터로서 건네 받는 것은 청취자 함수의 단순한 memory address이며 Flash Player는 그 memory address와 myListenerObj 인스턴스를 연결시켜주는 수단이 없기 때문이다.

이벤트 청취자의 관리
청취자 함수를 관리하려면 IEventDispatcher 인터페이스의 메소드를 사용한다. IEventDispatcher 인터페이스는 DOM 이벤트 모델에 있어서의 EventTarget 인터페이스의 ActionScript 3.0 버전이다. IEventDispatcher라는 이름에서는 Event 오브젝트를 송신(송출) 하는 것이 주된 목적인 것처럼 생각되지만 실제로는 이벤트 청취자를 등록, 확인, 및 삭제하는 목적으로 메소드를 사용할 기회가 가장 많다고 말할 수 있다. IEventDispatcher 인터페이스에는 다음의 코드에 나타난 5 개의 메소드가 정의되어 있다.

package flash.events
{
public interface IEventDispatcher
{
function addEventListener(eventName:String,
listener:Object,
useCapture:Boolean=false,
priority:Integer=0,
useWeakReference:Boolean=false):Boolean;

function removeEventListener(eventName:String,
listener:Object,
useCapture:Boolean=false):Boolean;

function dispatchEvent(eventObject:Event):Boolean;

function hasEventListener(eventName:String):Boolean;
function willTrigger(eventName:String):Boolean;
}
}
Flash Player API는 EventDispatcher 클래스에 IEventDispatcher 인터페이스가 implements 되고 있다. 이 클래스는 이벤트 플로우의 일부나 이벤트 타겟으로서 기능하는 모든 클래스에 대한 기본 클래스다. 예를 들어 DisplayObject 클래스는 EventDispatcher 클래스를 계승하고 있다. 이 때문에  표시 리스트내의 임의의 오브젝트는 IEventDispatcher 인터페이스의 메소드에 액세스 할 수 있다.

이벤트 청취자의 추가
addEventListener()는 IEventDispatcher 인터페이스로 가장 자주 사용되는 메소드다. 청취자 함수를 등록할 때 이 메소드를 사용한다. type 및 listener 의 2 개의 파라미터는 필수다. type 파라미터에서는 이벤트의 타입을 지정한다. listener 파라미터에서는 목적의 이벤트가 발생했을 때에 실행하는 청취자 함수를 지정한다. listener 파라미터에는 함수에의 참조 또는 클래스 메소드의 참조의 어느쪽이든 지정할 수 있다.

addEventListener() 메소드의 useCapture 파라미터를 사용하면 이벤트 플로우의 어느 단계에서 청취자를 액티브하게 하는지를 제어할 수 있다. useCapture에 true를 지정하면 그 청취자는 이벤트 플로우의 캡쳐 단계에서 액티브하게 된다. useCapture 에 false를 지정하면 그 청취자는 이벤트 플로우의 타겟 단계와 bubbling 단계에서 액티브하게 된다. 이벤트 플로우의 모든 단계에 있고 이벤트를 받으려면 useCapture 에 true를 지정했을 경우와 useCapture 에 false를 지정했을 경우의 양쪽 모두에 대해서 2 회 addEventListener()를 호출할 필요가 있다.

addEventListener() 메소드의 priority 파라미터는 DOM Level 3 이벤트 모델의 정식적 파라미터가 아니다. 이것은 이벤트 청취자를 보다 유연하게 편성하도록 ActionScript 3.0에서 독자적으로 제공되고 있는 파라미터이다. addEventListener()를 호출할 때에 priority 파라미터에 정수치를 지정하는 것으로 이벤트 청취자의 우선도를 설정할 수 있다. 디폴트치는 0이지만 부의 정수치 또는 정의 정수치를 지정할 수 있다. 지정한 수치가 높은 만큼 이벤트 청취자가 빠른 순서로 실행된다. 같은 우선도로 등록된 복수의 이벤트 청취자가 있는 경우 그것들은 등록순서에 의해서 먼저 등록한 이벤트 청취자가 빨리 실행된다.

useWeakReference 파라미터를 사용하면 그 청취자 함수에 대한 참조를 통상의 참조로 하는지 약참조로 하는지를 지정할 수 있다. 이 파라미터에 true를 지정하면 청취자 함수가 사용되지 않게 된 이후에도 메모리상에 계속 남는 것을 막을 수 있다. Flash Player는 "가베지 콜렉션"의 테크닉에 의해서 사용되지 않게된 오브젝트를 메모리로부터 삭제한다. 어느 오브젝트에 대해서 참조가 한 개도 존재하지 않을 때는 그 오브젝트는 더 이상 사용되지 않는다고 판단하여 약참조에의하여 참조 밖에 있는 오브젝트는 가베지 콜렉션의 대상이 된다.

이벤트 청취자의 삭제
불필요하게 된 이벤트 청취자를 삭제하려면 removeEventListener() 메소드를 사용한다. 불필요하게 된 청취자는 삭제하는 것을 추천한다. 필수의 파라미터는 eventName 및 listener의 2 개로 addEventListener() 메소드의 필수 파라미터와 같다. 위에서 이야기 했던 것과 같이 이벤트 플로우의 모든 단계에 있고 이벤트를 받는 경우는 useCapture 에 true를 지정했을 경우와 false를 지정했을 경우의 양쪽 모두에 대해서 2 회 addEventListener()를 호출한다. 그리고 양쪽 모두의 이벤트 청취자를 삭제하려면 useCapture 에 true를 지정했을 경우와 false를 지정했을 경우의 양쪽 모두에 대해 2 회 removeEventListener()를 호출할 필요가 있다.

이벤트의 송출
dispatchEvent() 메소드는 독자적인 이벤트 오브젝트를 이벤트 플로우에 송출하는 경우에 사용하는 상급 개발자 전용의 메소드다. 이 메소드로 지정할 수 있는 파라미터는 1 개로 Event 클래스 또는 그 서브 클래스의 인스턴스를 지정한다. 송출된 이벤트 오브젝트의 target 프롭퍼티에는 dispatchEvent()로 불려 간 오브젝트가 설정된다.

기존의 이벤트 청취자의 확인
IEventDispatcher 인터페이스가 갖추는 나머지 2 개의 메소드는 이벤트 청취자의 존재에 관한 유용한 정보를 취득하기 위해서 사용한다. 지정한 표시 리스트 오브젝트에 지정한 이벤트 타입의 이벤트 청취자가 등록되어 있는 경우 hasEventListener() 메소드는 true를 돌려준다. willTrigger() 메소드도 지정한 표시 리스트 오브젝트에 청취자가 등록되어 있는 경우에 true를 돌려주지만 willTrigger()은 지정한 표시 오브젝트 자체를 확인할 뿐만 아니라 이벤트 플로우의 모든 단계에 있어서의 그 표시 리스트 오브젝트의 조상도 모두 확인할 수 있다.

에러 이벤트의 청취자를 등록하지 않는 경우
에러 처리에 관해서 ActionScript 3.0에 있어서의 가장 중요한 메카니즘은 이벤트가 아니라 예외지만 비동기의 조작 (파일의 로드 등)에는 예외 처리를 사용할 수 없다. 비동기의 조작을 실행중에 에러가 발생하면 Flash Player 에 의해 에러 이벤트 오브젝트가 송출된다. 에러 이벤트에 대한 청취자를 작성하지 않은 경우 디버그판의 Flash Player는 발생한 에러에 관한 정보가 다이알로그 박스에 표시된다. 예를 들어, 파일의 로드 처리에 대해 무효인 URL를 지정하면 standalone의 디버그판 Flash Player에서 에러를 나타내는 다이알로그 박스가 표시된다.

에러 이벤트의 대부분은 ErrorEvent 클래스에 근거하고 있기 때문에 Flash Player는 이러한 메시지를 표시하기 위해 text라는 프로퍼티가 있다. 다만 StatusEvent 클래스와 NetStatusEvent 클래스의 2 개는 이것에 해당하지 않는다.

이러한 에러 이벤트가 발생해도 그에 따라서 SWF 파일의 실행이 정지하지는 않는다. 단지 디버그판의 브라우저 플러그인 또는 standalone의 Player 다이알로그 박스에 의해서 에러의 정보가 나타날 뿐이다.

    

설정

트랙백

댓글