Creative Wrong Answer


모든 이벤트는 typetarget 속성을 가지고 있다. 이것은 어떤 이벤트가 발생했는지 어떤 객체가 이벤트를 발생시켰는지에 대한 정보이기 때문에 꼭 필요하다.
EventDispatcher 가 이벤트를 Broadcase(전파) 하게 되면 Listener가 발생한 이벤트를 받게 된다.

이벤트는 두가지 형식으로 나눠진다.
스테이지에 보이는 객체가 발생시키는 이벤트와 보이지 않는 객체가 발생시키는 이벤트이다.

스테이지에 보이는 객체가 발생시키는 이벤트는 이벤트 흐름(event flow)에 따라서 이동하게 된다.
여기서 나오는게 버블링이다.
보이지 않는 객체가 발생시키는 이벤트는 이벤트 흐름을 타지 않고 해당 객체에 직접 등록된 listener 에서만 캐치 할수 있다.

Loader 같은 것이 이런 경우이다.

private function loadImage():void
{
	var loader:Loader = new Loader();
	loader.load( new URLRequest("http://localhost:8080/logo.gif") );
	loader.addEventListener(Event.COMPLETE, loadComplete);
}
위 소스에서 처럼 loader에 직접 listener를 붙이는 경우에만 loader 객체가 발생시키는 이벤트를 받을 수 있다.

보이는 객체가 발생시키는 이벤트는 이벤트 흐름을 탄다고 했는데. 이제 본격적으로 알아보자.

1. 어떤 이벤트가 발생한다. (마우스 클릭, 키보드 누르기, 등등)
2. 어플리케이션은 어떤객체가 이벤트를 발생시켰는지 찾기 위해서 하위 자식들을 검색해간다. (캡쳐)
3. 어플리케이션이 이벤트를 발생시킨 객체를 찾았다 (타겟)
4. 이벤트의 정보를 가지고 다시 어플리케이션으로 돌아온다. (버블)

대부분의 이벤트는 이 버블링 단계에서 listen 해서 사용하게 된다.
거품이 물 안에서 위로 올라오는 것처럼 이벤트를 발생시킨 객체에서 어플리케이션으로 올라오기 때문에 버블링이라고 하는게 아닐까 싶다.
거품이 위로 올라올때 중간에서 가로챌수 있는것처럼. 이벤트가 발생하게 되면 발생시킨 객체의 상위 parent 에 listener가 등록되어있다면 그 이벤트를 받아서 처리 할 수 있다.

아래의 화면은 이벤트가 발생하는 것을 보여준다.
빨간색과 파란색에는 각각 MouseEvent.CLICK 리스너가 붙어있다.





파란색 캔버스를 클릭하게 되면 파란색 캔버스가 클릭되었다는 메시지가 나온다.
빨간색 캔버스를 클릭하게 되면 빨간색 캔버스가 클릭되었다는 메시지가 나온 이후에 파란색이 클릭되었다는 메시지가 나오게 된다.

이벤트 흐름

빨간색 캔버스가 MouseEvent.CLICK 이벤트를 디스패치 한다.
캡쳐 단계 - 어플리케이션은 빨간색 캔버스를 찾아 들어간다 ( Application - blueCanvas - redCanvas )
타겟 단계 - 빨간색 캔버스를 찾았고 빨간색의 리스너에게 클릭되었다는것을 알려준다 (redCanvas Click)
버블 단계 - 이벤트를 가지고 어플리케이션으로 올라온다. (redCanvas - blueCanvas - Application)
                이때 blueCanvas 도 Click 이벤트 리스너가 붙어있기 때문에 리스너에 등록된 함수가 실행된다.
                (blueCanvas Click)

빨간색 캔버스를 클릭한 후에 나오는 메시지의 Phase 를 보면 Red Click - phase : 2 라고 되어있다.
phase가 2 이기 때문에 타겟 단계에서 이벤트를 받았다는 이야기이다. 이때 event.target 으로 빨간색 캔버스가 참조된다.
Blue Click - phase : 3 에서 phase가 3 이므로 버블 단계임을 알수 있다. event.target 은 여전히 빨간색 캔버스이다.

여기서 target 과 currentTarget 의 관계도 알 수 있다.

event.target 은 이벤트를 발생시킨 객체이다. 빨간 캔버스를 클릭한 후 캐치된 두개의 이벤트 모두 target 은 빨간 캔버스이다.
event.currentTarget 은 리스너가 붙어있는 객체이다.
RedClick 이벤트의 currentTarget 은 빨간색 캔버스 이지만 BlueClick 이벤트의 currentTarget 은 파란색 캔버스가 되는 것이다.

이 관계를 잘 고려해서 이벤트 모델을 구성해야 자잘한 에러를 막을 수 있다.

예를 들면 canvas 를 base로 커스텀 컴포넌트를 만들었는데 안에 라벨이 들어있는경우 event.target 으로 캔버스를 받고 싶었지만 라벨쪽이 클릭된 경우 target 으로 label 이 넘어와서 오류가 난다거나 하는 경우가 생기게 된다.
target 과 currentTarget 을 구분해서 사용하는 것은 쉬운듯 하면서도 빠뜨리기 쉬운 부분이다.

위의 예제에서 useCapture 를 체크 한 상태로 캔버스를 클릭 해보자.

useCapture Flag 는 capture 단계에서 이벤트를 사용할것인가에 관한 것이다.

파란색 캔버스를 클릭하게 되면 캡쳐 단계에서만 이벤트를 받게 되므로.. 아무런 이벤트도 발생하지 않는다. 파란색 캔버스가 클릭되었다는 메시지가 나와야 할것 같지만. 파란색 캔버스의 경우는 target 단계이므로 아무런 이벤트도 받을 수 없는 것이다.

빨간색 캔버스를 클릭하게 되면 빨간색을 찾아가는 동안에 만나게 되는 파란색캔버스만 이벤트가 발생하게 된다.

이렇게 useCapture Flag 를 true 로 설정하게 되면 타겟과 버블링 단계가 무시되고 오직 캡쳐 단계에서만 이벤트를 받게 된다.
자주 쓰이는 속성은 아니지만 꼭 필요하게 되는 경우가 생기기도 하기 때문에 알아두는 것이 좋다.

늦은 감이 있지만 이쯤에서 addEventListener 를 한번 보고 가야 할것 같다.


addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void
리스너에서 이벤트 알림을 받을 수 있도록 EventDispatcher 객체에 이벤트 리스너 객체를 등록합니다.

네번째 파라미터인 priority 는 우선순위에 관한 것이다 숫자가 높을수록 먼저 처리되고 숫자가 같은 경우 먼저 추가된 리스너 부터 처리 된다.
하지만 useCapture 보다 더 쓰이지 않는다.

마지막의 useWeakReference 가 있는데 이것은 이전 글 [2010/02/05 - [Flex/Event] - Flex Event 기본 설명 ] 에서 removeEventListener 를 명식적으로 사용하기 힘든 경우에 체크 한다고 이야기 했었다.

한번더 강조 하지만 addEventListener 는 가비지 컬렉터가 메모리 해제를 하지 못하는 가장 많은 경우이다.
꼭 removeEventListener 해주는 습관을 기르자.


위의 예제에서는 빨간색캔버스가 클릭되어도 파란색캔버스에 붙어있는 listener Function이 실행되게 되는데 파란색캔버스가 직접 클릭되었을때만 실행되도록 하기 위해서는 어떻게 해야 할까.

이럴때 사용하는것이 로그에 같이 찍히던 phase 이다.

파란색 캔버스의 리스너함수에 event.eventPhase가 2 일때만 실행되도록 함수를 구성하게 되면 파란색 캔버스가 직접 클릭되었을때만 함수의 내용을 실행하도록 만들수 있다.
예제 아래에 적어져 있듯이 2 이면 타겟 이기 때문에 파란색 캔버스가 직접 클릭되었다는것을 알수 있게 된다.
event.currentTarget 값이 buleCanvas 일때의 조건을 사용해도 결과는 동일하다

또는 빨간색캔버스의 리스너에서 e.stopImmediatePropagation() 이나 e.stopPropagation() 으로 끊어줘도 동일하게 결과가 나타난다.

하지만 지금의 예제는 이벤트를 받는곳이 두군데 이기 때문에 같은 결과가 나오는 것이지. 많약 어플리케이션에서도 이벤트를 리슨 하고 있다면. 다른 결과가 나오게 된다.

만약 어플리케이션에서 마우스 이벤트의 리스너가 대기 중이라면 파란캔버스에 phase 로 조건을 줘서 걸러냈을경우 어플리케이션에서는 이벤트를 받을 수 있다.
하지만 빨간색 캔버스에서 이벤트 흐름을 끊었을 경우 어플리케이션에서도 이벤트를 받을 수가 없다.
이 부분은 다음 포스트에서 확인 해보자.

지금까지 이벤트 흐름에 관해서 정리해 보았다.
Flex 에서 이벤트 흐름은 아무리 강조해도 지나치지 않는다. 많은 자료들을 보고 정리 하는 습관을 길러야 한다.
저작자 표시 비영리 동일 조건 변경 허락
신고

Comment 1