Flex: 타이밍 문제를 어떻게 할 것인가?
Flex에서는 여러가지 종류의 타이밍 문제가 발생한다.
XML에서 모든 걸 해결하게 되면 문제가 없지만,
Script단에서 뭔가 동적으로 시도하게 되면, 여러 가지로 문제가 발생하는데
이를테면
1. 이미지를 로딩하고
2. 이미지를 처리하는 일련의 코드가 있다고 하였을 때
1.에서 이미지를 로딩하는 것 자체가 별도의 thread로 동작하므로
non-block 상태로 바로 2.로 넘어가면서 문제가 발생한다.
Flex에서는 대부분 이 상황을 이벤트를 이용해서 처리하도록 되어 있지만, 각각의 경우에
모두 이벤트로 처리하는 것 만큼 귀찮은 것도 없다.
(한 가지 의미단위의 일을 처리하기 위해 수십개의 두, 세줄짜리 펑션을 병풍처럼 나열해 놓는 것이
얼마나 귀찮고 짜증나는 일인가!)
그래서 이벤트 안 구절에 펑션 자체를 구겨넣는 다음과 같은 짓도 가끔 하게 되었는데,
img.addEventListener(Event.COMPLETE,function temp():void {imgLoaded = true;});
이게 어려번 돌게 되면 문제가 발생된다.
이벤트의 시작 시점의 imgLoaded(의도) 와 실제 invoke 할때의 imgLoaded(알 수 없는 녀석)의
값이 달라지는 정도는 애교, 아예 다른 memory를 refer 하는 경우도 있다.
그래서 Flex에 sleep() 이 있었다면, 이런 짓이 필요가 없을텐데, 를 고민하다가
결국 조금 변태적으로 sleep() 비슷하게 구현하였다.
맞다. 타이머다.
타이머를 쓰면 간단한데, Flex에서 타이머 질을 좀 해보면 알겠지만, 매번 만드는 게 귀찮기도 하고
메모리 문제를 해결하는 것도 귀찮다. (Flex에서 이벤트 관련된 부분의 메모리 문제는 정말이지 최악이다)
그래서, 타이머를 이용해서 이런 짓을 해 봤다.
public static function avoidTimingProblem(actionFunction:Function, timeToRetry:Number = 500):void { var myTimer:Timer = new Timer(timeToRetry,1); myTimer.addEventListener(TimerEvent.TIMER, actionFunction,false,0,true); myTimer.addEventListener(TimerEvent.TIMER_COMPLETE, killTimer,false,0,true); myTimer.start(); } public static function killTimer(event:TimerEvent):void { event.target.stop(); delete Timer(event.target); }
(아래쪽의 killTimer()는 이것과 관련없이 타이머 쓸 때 항상 호출하는 용으로 만들어 둔 것이다.
관련된 내용은 이곳에 포스팅 해 두었다.)
호출은 요런식으로 이루어진다.
public function toDoWithMyCanvas(event:Event = null) { if (!mainCanvas) { avoidTimingProblem(toDoWithMyCanvas,100); return; } // your code(s) here. }
이렇게 되면 0.1초마다 mainCanvas 가 생성되었는지 (not null)인지 끊임없이 체크하여
생성된 순간 코드를 실행하고, 타이머를 깨끗히 정리 해 준다.
결국 타이머 사용을 간소화 해 준 것 뿐으로,
위의 예제만 보면 이벤트를 쓰는 게 더 좋아보이지만,
이를테면 XML을 한 네개쯤 불러와야 하는데, 각각이 다 불려져야 뭔가 할 수 있는 경우 라던지,
아니면, 위의 경우와 같이 이미지를 불러와서 처리하는 경우에, 몇개의 이미지가 모두
불려졌어야 하는 경우라던지, 그런식으로 여러 개의 복잡한 체크를 겪어야 하는 경우
이 방법은 좀 더 쉬운 코딩을 도와 줄 수 있을 것이다.
-> 이렇게 처리 할 수 있다.
public function imageProcessing(event:Event = null) { if (!img1.bIsLoaded || !img2.bIsLoaded ||img3.bIsLoaded) { avoidTimingProblem(imageProcessing); return; } }
// 참고 : bIsLoaded는 로딩 완료를 체크하기 위해서 Image에서 상속받은 클래스에서
내가 임의로 만든 property 이며 보통의 경우 width의 value 를 체크하거나,
loaderInfo를 이용해 체크하면 된다.