[ActionScript 3.0] Stage.invalidate()를 호출해도 Event.RENDER 이벤트가 발생하지 않는 문제 해결
[공지]이미지나 링크가 깨졌다면 댓글 부탁드립니다.
Adobe Flex가 아닌 Flash CS3, CS4, ActionScript 3.0로 개발해본 사람이면 Stage를 자주 접하게 된다. 하나의 ActionScript 3.0 애플리케이션은 Stage 하나를 가지고 있다. 이것은 모든 DisplayObject 계열의 객체가 addChild()를 통해 시각화 과정이 완료후에 그 객체의 stage속성을 통해 접근이 가능하다. 모든 DisplayObject 계열의 객체에서 stage속성에 접근할 수 있다는 것은 stage가 매우 중요하다는 것을 암시하고 있다. 그러므로 잘 알고 활용해야 삽질을 방지할 수 있지 않을까?
1. Stage.invalidate()와 Event.RENDER 이벤트의 이해
Stage 클래스에는 invalidate() 메소드가 있다. 이것을 호출하면 다음 렌더링 시점에 Event.RENDER 이벤트를 발생시킨다. 모든 DisplayObject 객체는 stage에 접근이 가능하므로 Event.RENDER 이벤트를 청취할 수 있다. 이는 애플리케이션 퍼포먼스를 향상시키고자 하는 개발자들이 반드시 알고 있어야할 사항이라고 생각한다. Stage의 invalidate()와 Event.RENDER 이벤트를 이용해 쓸데없는 렌더링을 예방함으로써 퍼포먼스를 향상시킬 수 있기 때문이다. 그 이유를 명확하게 알기 위해 다음 예제를 보자.
필자는 일반 ActionScript 3.0 프로젝트를 만들고 Sprite기반에서 애플리케이션을 만들고자 한다. 이때 두개의 클래스를 만드는데 하나는 Stage.invalidate()를 사용한 클래스이고 하나는 사용하지 않는것이다. 이 두개를 비교하면 Stage.invalidate()의 유용성을 확연히 알 수 있다.
InvalidateTest.as
package {
import flash.display.Sprite;
import flash.display.StageScaleMode;
import flash.display.StageAlign;
/**
* Stage.invalidate() 테스트 메인
* @author Yongho, Ji (jidolstar@gmail.com)
* @since 2009.6.1
*/
public class InvalidateTest extends Sprite
{
public function InvalidateTest()
{
super();
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
var button1:NotUseInvalidateButton = new NotUseInvalidateButton();
button1.setWidth( 100 );
button1.setHeight( 100 );
button1.backColor = 0xff0000;
button1.lineColor = 0x00ff00;
button1.x = 20;
button1.y = 20;
addChild( button1 );
var button2:UseInvalidateButton = new UseInvalidateButton();
button2.setWidth( 100 );
button2.setHeight( 100 );
button2.backColor = 0xff00ff;
button2.lineColor = 0x0000ff;
button2.x = 130;
button2.y = 20;
addChild( button2 );
}
}
}
위처럼 두개의 버튼 클래스를 만들었다. 2개 모두 폭, 높이, 배경색, 선색을 지정하도록 되어 있다. 결과는 비슷하다. 하지만 내부적으로 NotUseInvalidateButton은 내부에 Stage.invalidate()를 사용하지 않았고 UseInvalidateButton은 사용했다. 소스를 보자.
NotUseInvalidateButton.as
package
{
import flash.display.Sprite;
/**
* Stage.invalidate()를 사용하지 않는 Button
* @author Yongho, Ji (jidolstar@gmail.com)
* @since 2009.6.1
*/
public class NotUseInvalidateButton extends Sprite
{
private var _height:Number = 50;
private var _width:Number = 50;
private var _backColor:Number = 0xffffff;
private var _lineColor:Number = 0x000000;
public function NotUseInvalidateButton()
{
super();
}
public function get backColor():Number
{
return _backColor;
}
public function set backColor( value:Number ):void
{
_backColor = value;
drawNow();
}
public function get lineColor():Number
{
return _lineColor;
}
public function set lineColor( value:Number ):void
{
_lineColor = value;
drawNow();
}
public function getWidth():Number
{
return _width;
}
public function setWidth( value:Number ):void
{
_width = value;
drawNow();
}
public function getHeight():Number
{
return _height;
}
public function setHeight( value:Number ):void
{
_height = value;
drawNow();
}
public function drawNow():void
{
trace( "[NotUseInvalidateButton] drawNow" );
graphics.clear();
graphics.beginFill( backColor, 1 );
graphics.lineStyle( 1, lineColor, 1 );
graphics.drawRect( 0, 0, getWidth(), getHeight() );
graphics.endFill();
}
}
}
UseInvalidateButton.as
package
{
import flash.display.Sprite;
import flash.events.Event;
/**
* Stage.invalidate()를 사용하는 Button
* @author Yongho, Ji (jidolstar@gmail.com)
* @since 2009.6.1
*/
public class UseInvalidateButton extends Sprite
{
private var _height:Number = 50;
private var _width:Number = 50;
private var _backColor:Number = 0xffffff;
private var _lineColor:Number = 0x000000;
private var isDrawNow:Boolean = false;
private var isInvalidated:Boolean = false;
public function UseInvalidateButton()
{
super();
this.addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
}
private function onAddedToStage( event:Event ):void
{
this.removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
if( isInvalidated )
{
isInvalidated = false;
this.stage.addEventListener(Event.RENDER, onRender, false, 0, true );
this.stage.invalidate();
}
}
private function onRender(event:Event):void
{
if( this.stage )
{
this.stage.removeEventListener( Event.RENDER, onRender, false );
}
if( isDrawNow )
{
isDrawNow = false;
drawNow();
}
}
private function invalidate():void
{
if( this.stage )
{
this.stage.addEventListener(Event.RENDER, onRender, false, 0, true );
this.stage.invalidate();
}
else
{
isInvalidated = true;
}
}
public function get backColor():Number
{
return _backColor;
}
public function set backColor( value:Number ):void
{
_backColor = value;
isDrawNow = true;
invalidate();
}
public function get lineColor():Number
{
return _lineColor;
}
public function set lineColor( value:Number ):void
{
_lineColor = value;
isDrawNow = true;
invalidate();
}
public function getWidth():Number
{
return _width;
}
public function setWidth( value:Number ):void
{
_width = value;
isDrawNow = true;
invalidate();
}
public function getHeight():Number
{
return _height;
}
public function setHeight( value:Number ):void
{
_height = value;
isDrawNow = true;
invalidate();
}
public function drawNow():void
{
trace( "[UseInvalidateButton] drawNow" );
graphics.clear();
graphics.beginFill( backColor, 1 );
graphics.lineStyle( 1, lineColor, 1 );
graphics.drawRect( 0, 0, getWidth(), getHeight() );
graphics.endFill();
}
}
}
디버깅 모드로 프로그램을 실행해보면 콘솔창에 다음과 같이 출력된다.
[NotUseInvalidateButton] drawNow
[NotUseInvalidateButton] drawNow
[NotUseInvalidateButton] drawNow
[NotUseInvalidateButton] drawNow
[UseInvalidateButton] drawNow
NotUseInvalidateButton은 drawNow()메소드가 4번 호출되고 UseInvalidateButton은 1번만 호출된다. 이것만 보더라도 쓸데없는 렌더링을 줄여준 UseInvalidateButton 클래스가 더 잘 설계되었다는 것을 확인할 수 있다.
NotUseInvalidateButton를 잘 살펴보면 setWidth(), setHeight(), set backColor, set lineColor 를 호출할 때마다 drawNow() 메소드를 호출한다. 개발자라면 이 4가지 속성이 모두 적용된 다음에 drawNow()를 호출하여 한번만 그려주고 싶어질 것이다. 이때 유용하게 사용할 수 있는 것이 Stage.invalidate() 이다.
UseInvalidateButton을 보자 NotUseInvalidateButton보다 약간 복잡해보이지만 잘 따라가보면 어렵지 않게 분석이 가능할 것이다. 결국 4개의 속성이 설정되면 invalidate() 메소드가 호출되고 Event.RENDER 이벤트를 받는 onRender()에서 drawNow()가 호출되도록 한다. 이렇게 되면 4개든 여러개든 할 것 없이 렌더링에 영향을 주는 다중 속성을 설정할 때마다 drawNow()를 호출하여 그림을 그려주는 부담을 줄일 수 있다.
그림을 그리는 행위는 일반 속성을 설정하는 것보다 더 비싼 비용을 가진다. 그러므로 그림을 그리는 것은 되도록 한번에 처리할 수 있도록 하는 것이 애플리케이션 퍼포먼스 향상의 중요한 요소가 될 수 있는 것이다.
2. Stage.invalidate()의 버그와 해결방법
하지만 이렇게 좋은 Stage.invalidate() 가 있음에도 불구하고 실제로 이 메소드를 호출해도Event.RENDER 이벤트가 발생하지 않아 당황스러운 경우가 필자에게 있었다. 그래서 어떤 것은 drawNow()가 호출되고 또 어떤 것은 호출안되는 상황이 발생한 것이다. 너무도 어이가 없지만 Flash Player 10으로 넘어오면서도 이 버그는 아직까지도 Fix가 되지 않은 모양이다.
- Triggering stage.invalidate() during a "render" event listener fails.
- stage resize should invalidate the display list
위 링크는 모두 Adobe Bugs 관리 시스템에 등록된 것이다.(여러분도 가입해서 투표하길 바란다. 버그 시스템을 잘 이용하면 해결하지 못하는 문제도 쉽게 해결할 수 있을지 모른다. ^^)
Event.RENDER가 발생한 중간에 stage.invalidate()가 호출되면 이게 무시가 되나보다. 그래서 동작상으로는 문제없지만 개발자에게는 버그처럼 느껴질 수 있을지 모르겠다. 어쨌든 필자도 이 문제로 고민을 하다가 한가지 해결방법을 찾았는데 그것은 Event.ENTER_FRAME 이벤트를 이용하는 방법이다.
Event.ENTER_FRAME을 이용해서 stage.invalidate()의 버그를 말끔히 해결할 수 있다. 다음 코드는NotUseInvalidateButton을 Event.ENTER_FRAME을 이용하는 것으로 바꿔본 것이다.
NotUseInvalidateButton.as
package
{
import flash.display.Sprite;
import flash.events.Event;
/**
* Stage.invalidate()를 사용하는 Button.
* Event.ENTER_FRAME 로 Stage.invalidate() 버그 우회
* @author Yongho, Ji (jidolstar@gmail.com)
* @since 2009.6.1
*/
public class UseInvalidateButton extends Sprite
{
private var _height:Number = 50;
private var _width:Number = 50;
private var _backColor:Number = 0xffffff;
private var _lineColor:Number = 0x000000;
private var isDrawNow:Boolean = false;
private var isInvalidated:Boolean = false;
public function UseInvalidateButton()
{
super();
this.addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
}
private function onAddedToStage( event:Event ):void
{
this.removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
if( isInvalidated )
{
isInvalidated = false;
this.stage.addEventListener(Event.RENDER, onRender, false, 0, true );
this.stage.addEventListener(Event.ENTER_FRAME, onRender, false, 0, true );
this.stage.invalidate();
}
}
private function onRender(event:Event):void
{
if( this.stage )
{
this.stage.removeEventListener( Event.RENDER, onRender, false );
this.stage.removeEventListener( Event.ENTER_FRAME, onRender, false );
}
if( isDrawNow )
{
isDrawNow = false;
drawNow();
}
}
private function invalidate():void
{
if( this.stage )
{
this.stage.addEventListener(Event.RENDER, onRender, false, 0, true );
this.stage.addEventListener(Event.ENTER_FRAME, onRender, false, 0, true );
this.stage.invalidate();
}
else
{
isInvalidated = true;
}
}
public function get backColor():Number
{
return _backColor;
}
public function set backColor( value:Number ):void
{
_backColor = value;
isDrawNow = true;
invalidate();
}
public function get lineColor():Number
{
return _lineColor;
}
public function set lineColor( value:Number ):void
{
_lineColor = value;
isDrawNow = true;
invalidate();
}
public function getWidth():Number
{
return _width;
}
public function setWidth( value:Number ):void
{
_width = value;
isDrawNow = true;
invalidate();
}
public function getHeight():Number
{
return _height;
}
public function setHeight( value:Number ):void
{
_height = value;
isDrawNow = true;
invalidate();
}
public function drawNow():void
{
trace( "[UseInvalidateButton] drawNow" );
graphics.clear();
graphics.beginFill( backColor, 1 );
graphics.lineStyle( 1, lineColor, 1 );
graphics.drawRect( 0, 0, getWidth(), getHeight() );
graphics.endFill();
}
}
}
위에서 stage.addEventListener( Event.ENTER_FRAME )과 stage.removeEventListener( Event.ENTER_FRAME ) 이 추가된 것을 확인하자. 무작정 이벤트를 청취하고 있으면 안되므로 적절하게 삭제도 하고 있다.
이렇게 처리함으로써 stage.invalidate()가 제대로 작동안하더라도 drawNow()메소드가 호출이 안되는 경우는 없게 된다.
3. fl.core.UIComponent 수정하기
Flash의 UIComponent 를 보면 이것 stage.invalidate() 때문에 렌더링이 안되는 경우가 종종 발생한다고 한다. 필자는 Flash는 해본적이 없기 때문에 확실하게 모르지만 이것도 Event.ENTER_FRAME 을 이용해 해결할 수 있다. 그 방법은 다음 링크를 참고한다.
How to Fix the Flash CS3 Components
UIComponent의 callLater()가 어떻게 동작하는 것인지 이것을 보고 감을 잡을 수 있을 것이다. 결국 Event.RENDER, Event.ENTER_FRAME 으로 한다!
4. mx.core.UIComponent의 무효화 메소드들
Flex의 UIComponent에는 invalidateDisplayList(), invalidateProperties(), invalidateSize()와 같은 invalidate() 메소드가 존재한다. 이는 앞선 메소드들의 호출에 대해 각각 updateDisplayList(), commitProperties(), measure() 메소드가 다음 렌더링 시점에 호출되도록 하고 있다. 이는 invalidate/validate 패턴이다.
재미있게도 Flex에서는 Stage.invalidate()에서 처럼 동작하지 않는 버그는 존재하지 않는다. 어떻게 된 것일까?
사실 Flex 내부를 살펴보면 Stage.invalidate() 와 Event.ENTER_FRAME을 이용해 invalidate 계열의 메소드를 처리하도록 되어 있다. UIComponent 부터, LayoutManager, SystemManager 를 들춰보면 Event.RENDER와 Event.ENTER_FRAME을 가지고 invalidate/validate 패턴을 구현하고 있다. (Flex 개발자도 어쩔 수 없었나보다. ㅡㅡ;;)
이에 대한 자료는 아래 링크를 읽어보면 되겠다.
Flex internals: Setting a button label
Flex만 접해보고 ActionScript 3.0 학습에 소홀히 했다면 절대 이런 문제를 발견할 수 없었을 것이다.
정리하며
Stage.invalidate()가 호출할 때 때떄로 Event.RENDER가 호출되지 않는 문제는 버그가 아닐 수 있다. 원래 그렇게 만들어졌을지도 모른다. 하지만 개발자는 이것을 버그로 여긴다. 왜냐하면 보통 개발할때는 그런 것은 생각안하고 메뉴얼만 보고 당연히 그러겠지 생각하기 때문이다. 좀 황당하지만 버그 아닌 버그로 Flex 까지 다 까보게 되었다 ㅡㅡ;
Event.RENDER, Stage.invalidate() 모를때는 setTimeout()과 Timer를 이용해 invalidate/validate 패턴을 구현했었다. 아~ 무식은 용감하다. ㅋ
'Adobe Flash Platform' 카테고리의 다른 글
| [Adobe RIA 소식]Flash Builder 4 Beta 배포 (39) | 2009/06/01 |
|---|---|
| [어도비 ACC뉴스레터]Flex 차기버전의 이름이 공개되다. (0) | 2009/06/01 |
| [ActionScript 3.0] Stage.invalidate()를 호출해도 Event.RENDER 이벤트가 발생하지 않는 문제 해결 (17) | 2009/05/31 |
| Flash CS3, 4에서 간단한 Remoting 호출을 위한 클래스 (0) | 2009/05/30 |
| [ActionScript 3]Vector로 더 빨라진 JPG 엔코더(JPGEncoder) (1) | 2009/05/26 |
| [OkGosu.Net 세미나 후기]Flex로 구현하는 RIA, 위젯 개발 노하우 세미나 (21) | 2009/05/25 |




글의 마지막부분에서도 언급하셨지만, render 이벤트와 invalidate() 메소드는 정상적인 동작을 하고 있는게 맞습니다. ㅎㅎ
(메뉴얼 상에 표기된 내용으로도 그렇습니다.)
render 이벤트는 렌더링 직전에 발생하는 것이고, invalidate()는 작업 큐에 렌더링을 등록하는 것이이서, render 이벤트 시에는 이미 렌더링이 예약되어 있으므로, invalidate()가 아무런 추가 동작을 하지 않는 것이지요.
render 이벤트에서 invalidate()를 부를 일이 없도록 디자인하는 것이 효율적이고 또 아름다운 디자인이라는 의견입니다. ㅎㅎ
제가 궁금한 것이 그것입니다. RENDER이벤트에서 어떻게 invalidate를 어떻게 안부를 수 있을까요? 정확히 그 시점을 어찌 알 수 있는 것일까요?
Flash Player는 싱글스레드 기반이기 때문에, RENDER 이벤트 핸들러 내에서만 invalidate()를 실행하지 않도록 하면 됩니다. RENDER의 이벤트 핸들러가 실행을 마친 직후에는 곧바로 Flash Player의 렌더링이 시작됩니다.
충분히 이해했습니다.
멀티스레드가 아닌 싱글스레드 운영방식이기 때문에 Render 이벤트 핸들러외에서 invalidate를 호출하지 않으면 된다는 것 자체는 이해가 갑니다.
이벤트가 발생하면 그림을 그려주는 로직을 실행해주고 실제 그림을 그리는 것도 Render이벤트 핸들러가 완료가 다음 시점에 렌더링이 된다는 것도 이해가 되네요.
그러나 실제로 제가 테스트 할때는 Render이벤트 핸들러 내에서 invalidate를 사용하지 않았는데도 문제가 있던것 같았습니다. 말씀하신데로 싱글스레드 기반이기 때문에 핸들러 내에서만 직접 invalidate를 호출하지 않는다면 Event.RENDER 는 발생해야하는건데...
한가지더 궁금한 사항은 만약 Enterframe을 이용하는 것외에 다른 해결책이 있다면 왜 FLEX에서는 어찌보면 비효율적인 Enterframe을 이용한 것일까요?
뭔가 찬익님이 설명해주시는 것과 연관되어 제가 간과하고 있는 무엇인가 있는것 같습니다.
역시 지돌님.. ㅎㅎ
Flex에서 ENTER_FRAME과 RENDER를 같이 사용하는 이유는 조금 다른 곳에 있습니다.
예를 들면, stage 자체가 아직 로드되지 않은 경우도 있을 수 있고, 또는 보안 설정에 의해, B 객체에서 실행한 stage.invalidate()에 의해 A 객체가 RENDER 이벤트를 발생시키지 않는 경우도 있습니다.
또한 ENTER_FRAME시마다 매번 호출을 하는것이 아니라, 필요할 때에만 이벤트 리스너를 등록했다가, 사용이 끝나면 해제하므로, 효율성에는 문제가 없다는 의견입니다.
지돌님께서 테스트하신 문제점은 저도 직접 확인을 해봐야 알 수 있을 것 같습니다. 저도 일부 브라우저에서 stage와 관련하여 몇 가지 오동작을 본 적이 있어서요 ㅎㅎ
답변 또 한번 감사해요. ㅎㅎ
Display객체가 stage에 추가되는 시점은 Event.ADDED_TO_STAGE로 알 수 있기 때문에 stage.invalidate()를 실행할 수 있다고 생각합니다. 그러므로 실행자체는 문제가 될 것 같지 않고요.
ApplicationDomain영역이나 SecurityDomain영역이 서로 다른 객체에서 invalidate가 안먹을 수도 있다는 생각은 못해봤습니다. 좀더 생각해봐야할 것 같네요.
Enterframe도 필요할때 등록하므로 문제는 없어보이겠네요.
그래도 여전히.. invalidate() 자체로 해결할 수 있는 방안은 enterframe밖에 없는 것 같습니다. ^^;
의견 넘 감사하고요.
이런 답변이 올때마다 블로그의 재미가 더해지는 것 같습니다. 제가 블로그를 하는 이유가 바로 여기에 있죠. ^^
한동안 바빠서 자주 못 들어왔어요. ㅎㅎ
ADDED_TO_STAGE도 사소한 문제가 있긴 하지만, 일단은 Stage.invalidate()에 버그가 있는지 여부도 확실히 확인이 안된 상태라, 일단 이 문제는 패스 ㅎㅎ
Flex 2가 나온 이후로는 Sprite를 거의 써본적이 없어서, 코드들이 상당히 생소하게 느껴지네요. ㅎㅎ 옛날엔 이런 걸 어떻게 짰을까 싶기도 하구요. (물론 지금보다는 다소 간단한 구조였지만..)
그나저나 FB4가 나왔네요.. 어서 받으러 가지요 ㅎㅎ
FB4 소개해주셔서 바로 설치하고 바로 리뷰를 적어봤습니다. 고마워요 ^^
레퍼런스 보고 그냥 그렇구나... 생각했는데
지돌스타님은 분석까지 하고 버그까지 찾아내시네요.
대단 하십니다.
요즘들어서 지돌스타님 블로그에 하루에 몇번씩은 들어오게
되네요. 올려주신 글들 넘 잘보고 있습니다.
앞으로도 화이팅해주세요.~ 감사합니다.^^
감사합니다. 저도 부족하기 때문에 분석도 하고 정리도 하고 그럽니다. 대단할 것까지 없답니다. ^^
두 분의 좌담으로 읽는 사람까지 더욱 유익해 지네요. ^^ 좋은글 감사합니다.
안녕하세요.
stage.invalidate();는 버그가 아니라 그 방식이 원래 정상동작하는 방식으로 알고 있습니다. 다음프레임헤드로 진입하기전에는...
예를들어 stage.invalidate();들 첫프레임에 for문으로 100번호출해도 실제는 1번만 호출되듯이..render 이벤트가 시행중일때도 추가로 요청되는 invalidate는 무시됩니다.
실제 이렇게 만든이유는 다른게 아니라 하나의 약속이죠. 그러니까..보통 width, height에 어떤 값을 지정해서 그것이 setter로 지정되어 있을경우 invalidate처럼 약속해서 처리하지 않으면 100번의 요청이 들어왔을때 아마 다 수행하게될겁니다. 그런데 동일 프레임헤드상에서 100번의 요청이 들어와도 제일 나중것..그러니까..다음프레임헤드로 넘어가기 바로전에 한번만 수행토록 하면 아무리 많은 요청이 들어와도 이것을 무시할수있는거죠..사실 일반적인 부분보다 flash로 직접 UI core 컴포넌트를 만들때 활용하면 좋습니다.
그리고 이것은 stage.invalidate로 굳이 안하고 enterFrame으로도 구현할수 있습니다. 그러니까..invalidate메소드가 대단한게 아니라...하나의 약속인거죠...as2.0에서는 invalidate가 없을때 onEnterFrame으로 구현했었죠..
이건 지돌스타님도 잘알고 계실듯한데...제가 혹 이해를 잘못한것인지 모르겠네요.^^;
예 알고 있는 사실입니다. 그런데 아직까지 이해가 안가는 것은 Flash Player 가 싱글스레드이고 invalidate()를 호출했음에도 불구하고 가끔 이 Render 이벤트가 발생하지 않을때가 있다는 겁니다. 여러번 invalidate()를 호출했다면 적어도 1번이상 Render 이벤트가 발생되어야한다는 것으로 이해하고 있는데 그게 제대로 동작안하다보니 참 의아하더군요. 그래도 Render이벤트와 enterframe을 섞어서 해결했는데... 재미있게도 이 방법이 Flex에도 그렇게 했다는 겁니다. 저는 Render만 가지고 해결하고 싶은데 Adobe Flex개발자들도 그 방법으로 안된다는 것을 알고 있었을 것 같네요.
아...flex내부에도 그렇게되어있나요? 저는 최근 flex소스를 본적이 없어서요. 소스공개는 혹 adobe에서하는지 궁금하네요..제가 flex작업은 거의 하지 않다보니..as3.0처음나왔을때(3년전) 그땐 제가 어떻게 소스를구해서 UIComponent 구조를 제가 본적이 있거던요..그땐 enterFrame은 본적이 없고..저역시 자체 core를 만들어서 사용하는데..아직 한번도 그런애러를 겪은적이 없어서...
혹 최근 소스를 참조할수 있는방법이 있을까요?
opensource.adobe.com 에서 flexsdk를 다운받아 보시면 될겁니다. 제 글의 4번을 보시면 어떻게 찾는지 대충 나와있습니다. 찾아보시면 제가 언급한 내용의 코드가 있을거예요.
네..감사합니다.^^
[quote]Flex만 접해보고 ActionScript 3.0 학습에 소홀히 했다면 절대 이런 문제를 발견할 수 없었을 것이다.[/quote]라는 부분에서 찔끔 하네요
앞으로는 열심히 하겠습니다!!