AS3.0 클래스 구조의 여러가지 상황에서 부모, 자식 객체의 참조 방법
by 세계의끝 on 3.29, 2010, under 고수들은 가르쳐주지 않는 AS3.0 입문
fla 파일의 프레임에 코드를 잔뜩 늘어놓았던 시절에는, 모든 함수와 변수의 스코프가 동일하므로 참조하는 방법에 대한 고민을 거의 하지 않아도 좋았습니다. 말하자면 fla 프레임의 코드는 하나의 클래스이면서, 생성자 함수외에는 존재하지 않는 클래스라고 볼 수 있을겁니다.
그러나 클래스를 이용하여 객체를 생성하는 경우에는 그렇게 단순하게만 돌아가지는 않습니다. 필연적으로, 원하지 않아도 부모 객체와 자식 객체를 생성하게 되는데, 몇 가지 규칙을 알고 있어야만 올바른 객체간 통신을 할 수 있게 됩니다.
이 내용은 AS2.0을 다루던 초보 개발자들이 AS3.0에 와서 가장 먼저 부딪히는 부분이며, 가장 많이 헤메는 부분이기도 합니다. 이제까지 MovieClip 이나 Sprite 객체를 만들어 마우스 클릭 이벤트만 걸고 노는 것에만 익숙했던 분들은 이 포스트를 정독하시면 많은 것을 얻으실 수 있을겁니다. 그런 즉슨 이 포스트는 AS3.0 에 막 입문한 초보분들을 위한 포스트 입니다.
아래에 설명한 방법들은 객체간 통신을 하기 위해 사용하는 여러가지 방법들 입니다. 물론 이 외에도 다른 방법이 있을 수 있습니다만, 가장 사용빈도가 높고 반드시 알아야 하는 몇 가지 방법을 소개하겠습니다.
A. 부모 객체가 자식 객체를 참조
객체간 관계에서 가장 흔한 상황이 되겠습니다. 부모 객체는 다수의 자식 객체를 가질 수 있고, 자식 객체에 public 으로 선언된 변수나 함수에 대해서는 자식 객체의 객체이름을 통하여 참조할 수 있다는것을 모두들 잘 알고 계실겁니다. 코드로 보면 아래와 같죠.
아래는 부모 객체를 생성한 부모 클래스의 코드 입니다.
0 1 2 3 4 5 6 7 8 9 10 11 12 13 | package { import flash.display.Sprite; public class ParentClass extends Sprite { public function ParentClass() { var _childInstance:ChildClass = new ChildClass(); addChild( _childInstance ); _childInstance.doSomething(); } } } |
아래는 자식 객체를 생성한 자식 클래스의 코드 입니다.
0 1 2 3 4 5 6 7 8 9 10 11 | package { import flash.display.Sprite; public class ChildClass extends Sprite { public function doSomething():void { trace( "하위 클래스 : do something in ChildClass !!" ); } } } |
B. 자식 객체가 부모 객체를 참조 – 첫 번째 방법
자, 그럼 거꾸로 자식 객체가 부모 객체에 있는 함수나 변수를 참조하려면 어떻게 하면 될까요? 자식 객체에서 parent 키워드를 사용하면 자신을 addChild 한 부모에게 접근할 수 있습니다만, DisplayObject 상속구조상의 메서드, 속성만 사용 가능할뿐 부모 객체에 정의된 것을 사용할 수는 없습니다.
이것의 논리적 원인을 따져보자면 이렇습니다. 우리가 부모, 자식 객체를 맺어주는데 사용한 메서드는 addChild() 입니다. addChild() 메서드는 Sprite 클래스가 바로 윗 단계에서 상속한 DisplayObjectContainer 클래스의 메서드죠. 아래의 레퍼런스 스샷에서 보시는 바와 같이 parent 를 사용해도 반환되어 나오는 것은 DisplayObjectContainer 입니다.
다시말해, DisplayObject 상속 체인 구조[01] 에서 부모와 자식 객체간의 결합은 DisplayObjectContainer 가 담당하고 있다는 것이죠… 라는 내용은 당연스러운 사실이지만, 무심코 사용한 parent 역시 DisplayObjectContainer 형(type)을 반환 하므로, DisplayObjectContainer 를 상속한 Sprite 도, 그 Sprite 를 상속한 개별 클래스(ParentClass) 역시 DisplayObjectContainer 까지의 메서드, 속성만 사용할 수 있습니다.[02]
약간 어려운가요? 논리적 원인을 따지자니 오히려 어려워진 감이 있는데, 어쨌건 ParentClass 의 메서드나 속성을 사용하기 위해서는 ParentClass로 형 변환을 해줘야 한다는 것만 이해하고 있다면 오케이 입니다.
아래는 부모 객체를 만드는데 사용한 클래스 입니다.
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | package { import flash.display.Sprite; public class ParentClass extends Sprite { public function ParentClass() { var childInstance:ChildClass = new ChildClass(); addChild( childInstance ); } public function doSomething():void { trace( "상위 클래스 : do something in ParentClass !!" ); } } } |
아래는 자식 객체를 만드는데 사용한 클래스 입니다.
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | package { import flash.display.Sprite; import flash.events.MouseEvent; public class ChildClass extends Sprite { public function ChildClass() { // 클릭을 위한 RoundRect this.graphics.beginFill( 0x336699 ); this.graphics.drawRoundRect( 10, 10, 100, 100, 60 ); this.buttonMode = true; this.addEventListener( MouseEvent.CLICK, clickHandler ); } private function clickHandler( $e:MouseEvent ):void { trace( this.parent ); // 출력 : [object ParentClass] // this.parent 는 DisplayObject 구조의 메서드나 속성만을 사용할 수 있음. // 상위 클래스 형(type)으로 형변환(casting:캐스팅) 하면 public 멤버를 사용할 수 있음 ParentClass( this.parent ).doSomething(); // 아래는 컴파일 에러 // this.parent.doSomething(); } } } |
trace( this.parent ) 출력 결과에서 보는것과 같이 parent 는 확실히 부모 객체 자체 까지는 참조 가능하지만 parent 가 가리키고 있는 것은 부모 객체의 DisplayObjectContainer 형태이기 때문에 부모 객체의 doSomething() 을 호출하게 되면 컴파일 에러가 발생합니다.
그래서 위와 같이 ParentClass로 형변환을 해야 부모 객체의 메서드를 사용할 수가 있습니다.
또한 형변환은 아래와 같이 할 수도 있습니다.
0 1 | var parentInstance:ParentClass = this.parent as ParentClass; parentInstance.doSomething(); |
C. 자식 객체가 부모 객체를 참조 – 두 번째 방법
자식 객체에서 부모 객체의 public 메서드를 사용하는 방법은 B 케이스와 같이 형변환 하는 방법 외에도 한가지 더 있습니다. 부모객체가 자식객체에게 부모 객체 자신을 참조할 수 있는 참조(레퍼런스)를 넘겨주는 방법입니다. 아래와 같이 말이죠.
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | package { import flash.display.Sprite; public class ParentClass extends Sprite { public function ParentClass() { var childInstance:ChildClass = new ChildClass(); addChild( childInstance ); // 이렇게 자식 객체에게 this(부모 자신의 객체 레퍼런스)를 넘겨줌 childInstance.updateParent( this ); } public function doSomething():void { trace( "상위 클래스 : do something in ParentClass !!" ); } } } |
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | package { import flash.display.Sprite; import flash.events.MouseEvent; public class ChildClass extends Sprite { private var _parent:ParentClass; public function ChildClass() { // 클릭을 위한 RoundRect this.graphics.beginFill( 0x336699 ); this.graphics.drawRoundRect( 10, 10, 100, 100, 60 ); this.buttonMode = true; this.addEventListener( MouseEvent.CLICK, clickHandler ); } /** * 부모 객체의 레퍼런스를 저장함 (부모 객체에서 호출) * @param 부모객체를 인자로 받아 전역변수에 저장 */ public function updateParent( $parent:ParentClass ):void { this._parent = $parent; } private function clickHandler( $e:MouseEvent ):void { this._parent.doSomething(); } } } |
마치…부모가 통장과 도장과 비밀번호를 자식에게 알려주는 것과 같은 느낌이네요.
D. 자식 객체가 부모 객체에게 이벤트를 보냄
위의 B, C 케이스를 이벤트로 통신을 하는 형태로 바꿔보면 어떨까요? 흔히 사용하는 MouseEvent 도 이에 해당하지만, MouseEvent 같이 사용자의 인터랙션에 의한 이벤트는, 이벤트를 발생하는 객체(dispatcher:디스패쳐)가 하는일이 없는것처럼 보이므로 아래와 같이 일부러 디스패쳐를 사용하는 상황을 구성해보았습니다.
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | package { import flash.display.Sprite; import flash.events.Event; public class ParentClass extends Sprite { public function ParentClass() { var childInstance:ChildClass = new ChildClass(); addChild( childInstance ); childInstance.addEventListener( Event.COMPLETE, animationComplete ); } private function animationComplete( $e:Event ):void { trace( "부모 객체에서 자식 객체에 걸어놓은 Event.COMPLETE 를 캐치함 !!" ); } } } |
자식 객체를 만든 클래스 입니다. 클릭을 하게 되면 객체 자신에게 Event.ENTER_FRAME 을 걸게 되고 매 프레임마다 enterFrameHandler() 핸들러를 실행하게 됩니다. 자세한 내용은 주석을 참고하세요.
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | package { import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; public class ChildClass extends Sprite { public function ChildClass() { // 클릭을 위한 RoundRect this.graphics.beginFill( 0x336699 ); this.graphics.drawRoundRect( 10, 10, 100, 100, 60 ); this.buttonMode = true; this.addEventListener( MouseEvent.CLICK, clickHandler ); } private function clickHandler( $e:MouseEvent ):void { this.addEventListener( Event.ENTER_FRAME, enterFrameHandler ); } private function enterFrameHandler( $e:Event ):void { // x 가 200이 될 때까지 감속운동 (easeOut) this.x += ( 200 - this.x ) * 0.1; // 200이 되면 엔터프레임을 중단하고 Event.COMPLETE 를 dispatchEvent() 함 if ( Math.round( this.x ) >= 200 ) { this.removeEventListener( Event.ENTER_FRAME, enterFrameHandler ); this.dispatchEvent( new Event( Event.COMPLETE ) ); } } } } |
실제 작업에서는 이런 종류의 코드를 작성해야 하는 경우가 많을 겁니다. 자식 객체에서 발생한 어떤 상황을 모두 실행한 후, 그 결과를 부모에게 알리고 싶은거죠.
E. 부모 객체가 자식 객체에게 이벤트를 보냄
부모 객체가 자식 객체에게 이벤트를 보낼 경우도 있겠죠? 부모 객체 입장에서는 자식 객체의 public 멤버들은 모두 참조가 가능하므로 자식 객체의 메서드나 변수를 직접 참조하여 데이터를 전달하거나 메서드를 호출할수도 있습니다. 바로 A케이스와 같은거죠.
그러나 A 케이스의 경우 부모 객체가 자식객체의 public 멤버들이 뭔지 알고 있어야 합니다. 물론 Flash(Flex) Builder 나 FlashDevelop, 또는 FDT, 그리고 Flash CS5 같이 코드 힌트를 지원하는 에디터에서는 자식객체가 가지고 있는 public 멤버들을 볼 수 있지만, 여기서 말하는 것은 그런 기능적인 부분을 이야기 하는 것이 아니라 객체지향 프로그래밍에서의 설계 원칙의 문제입니다. 예를 들어보죠.
만약 부모 객체와 자식 객체가 서로 분리되야할 상황이 생겼습니다. A나 B 케이스는 부모 자식객체간에 서로 직접 참조하고 있으므로, 이 두 객체를 만든 클래스가 분리되는 순간 서로를 참조하고 있던 부분은 모두 컴파일 에러가 발생합니다. 이런 것을 보고 두 객체간 강한 결합을 했다고 표현하죠.
한편, D나 E 케이스는 이벤트를 통해 이 결합을 다소 약하게 만들 수 있습니다. 데이터를 이벤트를 통해 전달하고 이벤트를 보냈다고 어떤 행동을 강제하지 않습니다. 이벤트를 보내는 입장에서는 보내는 걸로 역할을 다 한 것이고 받는 입장에서는 받긴 받았지만 이것을 실행할지 말지는 자신이 결정할 수 있기 때문입니다.
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | package { import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; public class ParentClass extends Sprite { private var _roundRect:Sprite = new Sprite; private var _childInstance:ChildClass = new ChildClass; public function ParentClass() { // 클릭을 위한 RoundRect _roundRect.graphics.beginFill( 0x996633 ); _roundRect.graphics.drawRoundRect( 10, 10, 100, 100, 60 ); _roundRect.buttonMode = true; _roundRect.addEventListener( MouseEvent.CLICK, clickHandler ); addChild( _roundRect ); addChild( _childInstance ); } private function clickHandler( $e:MouseEvent ):void { // _roundRect 의 MouseEvent.CLICK 를 캐치하면 // _childInstance 객체에 MouseEvent.ROLL_OUT 이벤트를 보냄 _childInstance.dispatchEvent( new MouseEvent( MouseEvent.ROLL_OUT ) ); } } } |
부모 객체에서 사용자의 인터랙션에 의해 발생한 MouseEvent.CLICK과는 다른 이벤트를 고르느라 자식 객체에는 MouseEvent.ROLL_OUT 를 보내는 다소 엉뚱한 예제 입니다만, 이벤트는 이렇게도 할 수 있다는것을 보여주는 예시라고 볼 수도 있겠습니다.
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | package { import flash.display.Sprite; import flash.events.MouseEvent; public class ChildClass extends Sprite { public function ChildClass() { // ChildClass 객체의 존재를 확인하기 위한 RoundRect this.graphics.beginFill( 0x336699 ); this.graphics.drawRoundRect( 120, 10, 100, 100, 60 ); this.buttonMode = true; this.addEventListener( MouseEvent.ROLL_OUT, rollOutHandler ); } private function rollOutHandler( $e:MouseEvent ):void { trace( "부모 객체가 자식 객체에게 dispatchEvent() 한 MouseEvent.ROLL_OUT 을 캐치함 !!" ); } } } |
부모 객체(왼쪽에 그려진 RoundRect 그림)를 클릭하면 자식 객체에게 MouseEvent.ROLL_OUT 이벤트를 발생시킬수가 있습니다. 또한 자식객체에는 addEventListener( MouseEvent.ROLL_OUT ) 가 걸려 있으므로 자식 객체를 표시한 오른쪽 RoundRect 그림에 마우스를 올렸다가 밖으로 빼도 동일한 이벤트가 발생하게 됩니다.
F. 이벤트 발생위치를 바꿈
E 케이스의 코드는 부모객체가 자식객체에게[03] dispatchEvent() 메서드를 사용한 것이지만, 반대로 부모객체 내부에서 dispatchEvent() 를 하고 자식객체에서 이것을 addEventListener() 할 수도 있습니다.
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | package { import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; public class ParentClass extends Sprite { private var _roundRect:Sprite = new Sprite; private var _childInstance:ChildClass = new ChildClass; public function ParentClass() { // 클릭을 위한 RoundRect _roundRect.graphics.beginFill( 0x996633 ); _roundRect.graphics.drawRoundRect( 10, 10, 100, 100, 60 ); _roundRect.buttonMode = true; _roundRect.addEventListener( MouseEvent.CLICK, clickHandler ); addChild( _roundRect ); addChild( _childInstance ); } private function clickHandler( $e:MouseEvent ):void { // 이번에는 부모 객체인 this 에 dispatchEvent() 를 함 // _childInstance 객체에서 addEventListener() 하고 있건 말건 무조건 이벤트가 발생 this.dispatchEvent( new Event( Event.SELECT ) ); } } } |
아래는 자식 객체를 만드는 클래스 입니다. 자세한 내용은 주석을 참고하세요.
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | package { import flash.display.Sprite; import flash.events.Event; public class ChildClass extends Sprite { public function ChildClass() { // ChildClass 객체의 존재를 확인하기 위한 RoundRect this.graphics.beginFill( 0x336699 ); this.graphics.drawRoundRect( 120, 10, 100, 100, 60 ); // 이 객체가 addChild() 되면 핸들러 실행 // 즉, 어떤 객체의 자식 객체가 된 상황 this.addEventListener( Event.ADDED, addedHandler ); } private function addedHandler( $e:Event ):void { // 어떤 부모 객체인지는 모르겠지만 부모 객체에 addEventListener() 를 걸어놓음 // addEventListener() 는 ParentClass 형(type)이 아니더라도 사용할 수 있으므로 캐스팅이 필요 없음 this.parent.addEventListener( Event.SELECT, selectHandler ); } private function selectHandler( $e:Event ):void { trace( "부모 객체의 이벤트를 자식 객체에서 캐치함 !!" ); } } } |
또는 반대로, 자식 객체에서 this.addEventListener() 하지 않고, 부모객체에서 이벤트가 일어나도록this.parent.dispatchEvent() 한 후, 부모객체가 this.addEventListener() 까지 하게 할 수도 있습니다. 이벤트가 발생(dispatchEvent)하는 위치만 다를뿐 부모, 자식 객체간은 서로를 자유롭게 참조할 수 있으므로 addEventListener() 메서드는 어디나 걸어 놓을 수 있는 것이죠.
이렇게 부모, 자식 객체간의 여러가지 상황에서 서로를 참조하는 방법에 대해 알아보았습니다. 어떤 방법이 절대적으로 옳지 않으므로 상황에 따라 적절하게 사용하면 됩니다. 또한, 어떤 방법이 절대적으로 옳은건 아니지만, 모든 방법을 제대로 이해하고 있어야 합니다. 그 만큼 객체 지향 프로그래밍에서 가장 기초적이고 중요한 내용입니다.
이해가 잘 안되는 케이스가 있다면, 빈 fla 파일에 ParentClass 를 도큐먼트 클래스로 설정하고 컴파일을 해 보세요.
* * *
만약 이벤트와 함께 데이터를 보내야 할 필요가 있을 경우에는 커스텀 이벤트를 사용하면 됩니다. 커스텀 이벤트는 이 포스트의 범위를 벗어나는 내용이므로 “이벤트에 뭔가 같이 보내보자 – 커스텀 이벤트 만들고 사용해보기” 를 읽어보시기 바랍니다.
또한, 객체간 더욱 약한 결합을 구현하기 위한 별도의 방법으로는 옵저버 디자인 패턴을 이용하는 방법이 있습니다. “Observer Pattern 옵저버 패턴 – 이벤트 디스패처를 이용해 구현” 을 참고하세요.
이 포스트는 부모, 자식 객체간 참조 방법을 다룬 글이었습니다. 객체가 아닌 상위 클래스와 하위 클래스의 참조 방법에 대한 글 “AS3.0 클래스의 상속(extends)구조에서 상위, 하위 클래스의 메서드 호출방법” 도 초보 개발자 여러분들에게 많은 도움이 될 것입니다.
- Object – EventDispatcher – DisplayObject – InteractiveObject – DisplayObjectContainer – Sprite [↑]
- Object, EventDispatcher, DisplayObject, InteractiveObject, DisplayObjectContainer 의 메서드, 속성만 사용할 수 있고, Sprite 이하의 메서드, 속성은 사용할 수 없습니다. [↑]
- 즉, 자식객체의 입장에서 보면 this.dispatchEvent() 된 것입니다. [↑]

Blog under the Creative Commons Attribution-NoDerivs 3.0 License
4월 1st, 2010 on am 10:48
안녕하세요^^
객체간의 통신에 대한 문제는 항상 고민하고 있었던 부분인데..
어플리케이션 단위가 커지면 커질수록 저도 모르게 커스텀 이벤트의 남발을 하게 되는경우도
있더군요.
이벤트로 먼가를 주고 받지 않을경우에는 굳이 커스텀 이벤트를 쓰지 않구 내장 이벤트 타입으로만 주고 받는편이 좋을지…
Tweener 형태에서 많이 쓰이는 오브젝트형태로 만들어 통째루 날려 버리는 방법 또한 고민되어 지는 부분이더군요.
오늘 하루도 좋은 하루 되시고 좋은 정보에 대한 다시 한번 감사의 말씀 드립나다^^
4월 1st, 2010 on am 11:02
선택의 문제겠죠.
커스텀 이벤트는 전달해야할 데이터가 있을경우엔 확실히 만들수밖에 없겠고요.
Event.COMPLETE 정도만 보내도 무방하다면 그것도 역시 불필요한 커스텀 클래스를 만들필요는 없는거죠.
그런데 한편으로는 보내는 데이터가 없어도 이벤트의 성격을 명확히 하고자 커스텀 이벤트를 만들기도 합니다. 그러니까…
SortEvent 라던지, GalleryEvent 같은것 말이죠.
아무래도 다른사람이(물론 코드를 작성한 본인조차도) 코드를 읽기가 수월해지겠죠?
방문 고맙습니다 ^^
4월 1st, 2010 on pm 5:57
안녕하세요. 좋은 글 잘 읽고 갑니다. ^^
4월 1st, 2010 on pm 6:17
료님은 읽을 필요가 없는 내용이잖아요 ^^
4월 1st, 2010 on pm 9:00
매번 고민하던 내용이었는데 잘 정리해주셔서 도움이 많이 되었습니다.
4월 1st, 2010 on pm 10:44
티오엠님까지 왜이러세요 ㅎㅎ
5월 18th, 2010 on pm 5:32
안녕하세요 구글 검색해서 이것저거 보다가 여기까지 왔습니당.
아직도 가물가물해서 읽고 또읽고 가야하네요 ㅠㅠ
좋은글 감사합니다!
5월 18th, 2010 on pm 6:44
읽어보는 것도 물론 중요하지만, 간단하게나마 코딩을 직접 해보는것이 훨씬 빠르게 이해 될겁니다.
마치… 손가락으로 체득하는 느낌이랄까요? ^^
4월 2nd, 2011 on pm 8:38
현재 플렉스로 쇼핑몰을 개발하고 있는중입니다.
이벤트 버블링으로 자식이 부모에게 이벤트를 전달하는 방법은 알고 있어서
약한 결합을 할 수 있어 좋았습니다
하지만 항상 부모는 자식.dispatchEvent를 하여서 강한 결합을 하고 있는 것 같아서
항상 고민이었는데 저에게 단비와 같은 포스트였습니다
아무리 구글링해도 답이 나오지 않았는데 여기에 구세주가 있었군요
정말 잘 읽고 갑니다 구글링과 블로그가 없다면 아마 제 프로젝트는 진행되지 못할거 같아요 ㅎ
자주 들르겠습니다
4월 2nd, 2011 on pm 8:58
이 포스트의 초반부에 AS2.0을 다뤄본 초보 개발자가 읽으면 좋은 글이 될 수 있겠다고 썼는데, 단비님(사용하시는 닉네임은 아닌것 같지만)과 같은 다른 언어로부터 와서 RIA 성향의 개발을 하고 있지만 액션스크립트에는 익숙하지 않은분들에게도 참고가 될만한 내용이 있을것 같군요.
그리고 제 블로그는 독자 대상이 대상이니만큼(구글링을 잘 하지 않는 초보개발자 대상) 네이버에서 검색해도 블로그 섹션에 노출되도록 해 놓았습니다.
방문해주셔서 감사합니다. ^^
4월 2nd, 2011 on pm 8:52
아 그리고 자식 객체에서 부모객체에게 이벤트를 전달하는 방법은 자식객체에서
this.parent.dispatchEvent()한후 부모에서 잡는 방법도 있겠지만 이벤트 버블링으로 전달할 수도 있잖아요
그런데 부모에서 자식객체에게 이벤트를 전달하는 방법은 부모에서 이벤트를 발생시키고
자식객체에서 this.parent.addEventHandler()하는 방법밖에는 없는건가요??
버블링은 루트에서 이벤트가 발생한 객체까지만 왔다가 다시 돌아가는 거라서
부모객체에서 발생한 이벤트는 루트에서 부모객체 사이객체까지만 왔다가서
자식객체까지는 버블링으로 해결이 안되네요
4월 2nd, 2011 on pm 9:49
dispatchEvent()가 어디서 일어나야 하는지에 대한 문제겠죠.
자식 객체에서 일어나도 관계 없다면 부모객체 내부에서 this.childInstance.dispatchEvent() 하면 될테고요.
this.parent.dispatchEvent() 하는 경우, 자식 입장에서는 dispatchEvent( new 이벤트클래스(이벤트종류) ) 의 ‘이벤트클래스’와 ‘이벤트종류’에 해당하는 것을 알고 있어야 하기 때문에 부모객체를 이미 상당히 많이 알고 있다는 전제를 하고 있는 것이나 마찬가지 입니다.
당연히 약한결합을 하는데 부담이 따를 수 밖에 없겠죠.
애초에 이벤트 구조라는 것이 그렇게 만들어져 있기 때문에 엄밀히 말해서 이벤트 구조는 약한 결합을 하기에는 뭔가 부족하다는 의견도 있습니다.
어차피 부모는 자식을 생성했으니 잘 알 수 밖에 없으므로, 부모에서 자식으로 향하는 결합에 한해 어느정도는 결합을 강하게 만들어도 무방하다는 지점에서 시작하면, 부모객체 자신의 this 참조를 넘겨준다거나, 부모객체의 함수를 자식객체의 함수에 인자로 넘겨준다거나 하는 등의 방법을 통해 이벤트를 대체할 수 있는 여러 가지 방법도 모색해 볼 수 있을 겁니다.
4월 2nd, 2011 on pm 9:58
아 답변 정말 감사합니다 ^^* 트위터도 아닌데 이렇게 빠르게 답변이 감동입니다
아 그리고 마지막 F.번에서 부모에서 자식객체 이벤트 전달이 되지 않더군요
부모에서 this.dispatchEvent() 이벤트종류는 제가 커스텀했습니다
자식객체에서 this.parent.addEventListener()로 잡았는데 이벤트 전달이 안됩니다
혹시나 오타가 있나 검토해보았지만 부모에서 this.자식이름.dispatchEvent하면
자식에서 잘 잡던것이 이 포스트를 보고 F번을 적용하여
부모에서 그냥 this.dispatchEvent를 하고 자식에서
this.parent.addEventListener를 하니 잡지를 못합니다 ㅠㅠ
하지만 답변에서 this.childInstance.dispatchEvent() 란 것이 있었군요…
이것을 쓰면 될것 같습니다만 왜 전 F번이 안됐는지 또 끙끙 속앓이 시작됐습니다 ㅠㅠ
4월 2nd, 2011 on pm 10:19
제 블로그에 댓글이 달리면 저에게 바로 노티스 되도록 해 놓았기 때문에
제가 pc 앞에 있는 상태라면 거의 실시간으로 답변드릴 수 있습니다.
트위터나 페이스북과 응답속도는 동일한 셈이죠.
위의 모든 예제는 테스트를 이미 했으므로 F 항목 자체가 동작하지 않는다는 말씀은 아닌듯 싶고, 쓰신 내용만으로는 어느 부분의 문제인지 알기는 힘들군요.
차근차근 잘… 살펴보세요. ^^
4월 2nd, 2011 on pm 10:02
아.. this.childInstance가 제가 사용하던 this.자식이름 이었군요
저는 또 this.childInstance라는 속성이 있는 줄 알았습니다 착각했어요
4월 2nd, 2011 on pm 10:20
네 맞습니다. ㅎㅎ
4월 3rd, 2011 on am 3:43
아! 그렇군요 어쩐지 답변이 빠르다고 생각했습니다 감사합니다 ㅎㅎ
F항목이 안되는 원인을 찾아냈습니다 현재 새벽3:40인데 참 코딩하다보면 어떤부분에서 해메게 되는데 알고 보면 정말 간단한 것이 많습니다
제가 부모객체 -> HBox -> VBox -> 에 자식객체가 있었던 거였습니다
저놈들이 눈에는 잘 보이지 않는것들이라 부모객체와 바로 자식객체라고 착각했습니다
this.parent하면 바로 위 부모 VBox를 의미했던 거였어요 ㅠㅠ
this.parent.parent.parent를 하니 부모객체 이벤트를 잘 잡아내었습니다
F항목 이상무!
5월 14th, 2011 on pm 10:38
몇번이나 봤었던건데,, 오늘에서야 조금 이해가 되네요,, ㅎ;;;
클래스간 이벤트 처리하는게 왜이렇게 어려운건지,,;;
클래스로 코딩했다가 다시 프레임으로 옮기고 클래스로 코딩했다가 옮기고,,ㅎㅎ;;;
아직 완벽하게 이해는 못해서;; 더 열심히 봐야겠네요 ^^;;
앞으로도 좋은글 부탁드리겠습니다~
5월 15th, 2011 on am 12:50
여석님처럼 한 포스트를 여러번 읽는 분들이 있어서 보람이 느껴집니다.
이벤트 처리에서는 이벤트 처리에서는, “이벤트를 주고 받는 객체가 동일해야 한다”는것과, 그 “주고받는 이벤트 역시 객체다” 라는 것을 항상 기억하고 있으면 대부분의 문제가 눈녹듯 해결될겁니다. ^^
5월 25th, 2011 on am 2:18
와우. 정말 좋은 글이에요. 저도 자주 와야겠어요. 무브, 버튼 이런거나 만지작 거리다가 정말 as3.0으로 갈아타고 싶었거든요. 이번엔 힘을 내야겠습니다. ^^ 감사합니다. 자주 올게요.
5월 27th, 2011 on pm 4:57
힘내서 훌쩍 뛰어넘으세요 ^^
7월 5th, 2011 on pm 5:08
좋은 글 감사합니다 ^^
궁금한 점이 있는데
만약
부모sprite와
자식movieClip에
mouseDown 이벤트가 두곳에 addEvent 되어있을 경우에
자식 mouseDown이 먼저 일어나고
부모 mouseDown이 다음으로 발생하는 걸로 알고있는데
애초에 자식 event만 발생을 시키고
부모 event를 발생 시키지 않는 방법은 없을까요??
7월 5th, 2011 on pm 5:26
이런..
쓸대 없는 질문이 였군요.;;
이벤트에 stopImmediatePropagation 함수를 호출하면 그냥 해결이 되는군요;;
7월 5th, 2011 on pm 5:31
질문 내용에
“자식 event 가 발생할 경우” 라는 조건이 추가되어야 겠죠? 부모 event 핸들러도 나름 다른 용도가 있을테니까요.
이벤트가 이미 발생하고 난 후 에는 객체.mouseEnable 속성의 변경이 영향을 미치지 못하므로, 이런 경우에는
자식객체의 이벤트 핸들러 함수에서 Event 객체의 stopPropagation() 또는 stopImmediatePropagation() 을 호출하여 처리하시면 되겠습니다.
—————————–
라고 써 놓고 보니 이미 자답을 하셨군요 ㅎㅎ
10월 11th, 2011 on pm 3:39
세계의끝 님 같은 사수가 필요해요 ㅠㅠ
10월 11th, 2011 on pm 3:46
주변에 잘 찾아보시면 좋은 사수가 있을지도 모릅니다.
같은 회사가 아니라도 말이죠 ^^
1월 27th, 2012 on pm 7:26
이 글을 10번 정도 보고
게임을 만들어 가면서 모든 경우를 다 시도해 보았습니다.
거의 한 달 동안 머리를 굴린 결과 조금은 이해할 수 있어서 참 기쁩니다.
그래도 애매한 것이 생겨서 질문 드립니다.
자식 객체가 부모 객체를 참조의 첫번째 방법에서 쓰는 casting 방식은
강제로 변환해 주는 것이라서 좀 위험한거 아닌가요?( 극히 개인적인 생각입니다)
저는 처음에 게임을 만들때 잘 몰라서 첫 번째 방법으로 계속 참조를 시도 했었습니다.
그런데 형 변환 하는 것 자체가 그리 좋은것이 아니라고 들어서…(그냥 들은것입니다)
의견을 듣고 싶어서 댓글을 남깁니다.
첫 번째와 두 번째 중에 어떤게 더 괜찮은 건가요??
둘다 비슷한 것 같지만 제가 좀 머리가 나빠서요 ㅎ
부탁드립니다 ^^
상관없으면 상관없다고 이야기 해 주셔도 되요 !!!
- 이 블로그의 글들은 아무것도 모르는 저에게 정말 큰 도움이 되고 있습니다 ㅠㅠ -
1월 28th, 2012 on am 6:42
형변환에 대한 약간 잘못된 정보를 가지고 계시는군요. ^^
형변환은 위험한 줄타기를 하고 있는 것이 아니라, 객체지향 프로그래밍(OOP)의 꽃이라고 할 수 있을 정도로 개발자에게 상당한 이득을 가져다 주는 기법 입니다.
형 변환이 잘못되었을 경우에는 어떤 경우라도 컴파일러가 에러를 뿜어주므로 형 변환의 위험도(?)에 따른 방법 선택이라면, 첫번째, 두번째 어떤 방법을 사용하셔도 무방합니다.
두 번째 방법은 참조를 넘겨줘야 하는 함수가 존재해야 하므로 클래스가 길어지는 단점이 있는가 하면, 명시적으로 “부모의 참조를 받았다” 라는 효과가 존재하므로 장점도 존재한다고 볼수도 있겠습니다.
따라서 “두 가지 방법 사이에 약간의 장단점은 존재하되 그닥 차이는 없다. 상황에 맞춰 쓰시라” 정도가 답이 되겠습니다.
또한 형 변환에 대한 글은 이 블로그에 꽤 있으므로 읽어보세요. 아래 링크 포스팅부터 읽어보시면 좋겠네요. http://ufx.kr/blog/539