참고 : http://www.flexlive.net/?p=102
         http://livedocs.adobe.com/blazeds/1/blazeds_devguide/lcconfig_3.html

BlazeDS 에서는 rtmp 채널을 지원하지 않기 때문에, 디폴트로 폴링 방식으로 메세징을 지원 합니다.
이런 사실 때문에, real-time messaging을 지원하지 않을거라는 착각을 할 수 있는데 다양한 테크닉으로 real-time messaging을 구현할 수 있습니다. 하지만 앞으로 소개될 테크닉들은 http-based 이기 때문에 독자적인 socket을 사용하는 lcds에 비해 속도와 동시접속에 있어서 뒤쳐질 수 밖에 없습니다.


Simple Polling

이 방식은 real-time의 효과를 볼 수 없는 기본적인 polling 입니다. 일정한 간격으로 요청(poll)하고 응답(ack) 받습니다. 만약 요청 했을 때, 다른 client로 부터 메세지가 들어와 있지 않다면 비어 있는 응답을 받습니다.

설정 방법은 다음과 같습니다.
<channel-definition id="polling-amf" class="mx.messaging.channels.AMFChannel">
    <endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/amfpolling" class="flex.messaging.endpoints.AMFEndpoint"/>
    <properties>
        <polling-enabled>true</polling-enabled>
        <polling-interval-seconds>4</polling-interval-seconds>
    </properties>
</channel-definition>



Piggybacking Polling
이 방식은 Simple Polling에서 일정한 간격에 의한 poll 이전에 다른 client의 메세지가 들어와 있을 경우, 다른 어떤 요청(Producer 또는 RemoteObject)을 보낸다면 그에 대한 결과와 더불어 메세지도 함께 응답 합니다.

설정 방법은 다음과 같습니다.
<channel-definition id="polling-amf" class="mx.messaging.channels.AMFChannel">
    <endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/amfpolling" class="flex.messaging.endpoints.AMFEndpoint"/>
    <properties>
        <polling-enabled>true</polling-enabled>
        <polling-interval-seconds>4</polling-interval-seconds>
        <piggybacking-enabled >true</piggybacking-enabled >
    </properties>
</channel-definition>



Long Polling

이 방식은 polling 이지만 다른 client로 부터 메세지가 올 때까지(또는 설정한 기간 만큼) poll을 잡아 놓음으로써 real-time의 효과를 볼 수 있습니다.

설정 방법은 다음과 같습니다.
wait-interval-millis : (default 0) poll 의 대기시간 입니다. -1의 경우 다른 client의 메세지가 올 때까지 무한대로 기다립니다.
max-waiting-poll-requests : 대기하는 poll의 갯수입니다.
<channel-definition id="long-polling-amf" class="mx.messaging.channels.AMFChannel">
    <endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/amfpolling" class="flex.messaging.endpoints.AMFEndpoint"/>
    <properties>
        <polling-enabled>true</polling-enabled>
        <wait-interval-millis>-1</wait-interval-millis>
        <polling-interval-millis>100</polling-interval-millis>
        <max-waiting-poll-requests>50</max-waiting-poll-requests>
    </properties>
</channel-definition>



Streaming

HTTP1.1 스펙의 open connection 기능을 이용함으로써, 서버 push를 구현하는 방법 입니다.
서버 push이기 때문에 real-time 그 자체라고 할 수 있습니다.

설정 방법은 다음과 같습니다.
max-streaming-clients : open connection의 갯수입니다.
<channel-definition id="streaming-amf" class="mx.messaging.channels.StreamingAMFChannel">
    <endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/streamingamf" class="flex.messaging.endpoints.StreamingAMFEndpoint"/>
    <properties>
        <max-streaming-clients>10</max-streaming-clients>
    </properties>
</channel-definition>



퍼포먼스는 Stream -> long polling -> piggybacking polling -> simple polling 순으로 좋습니다.
설정 가능한 프로퍼티는 참고 문서를 참조 하세요.
신고
Posted by 째코
그냥 만들어 봤어요.
검쉰님이 스타일 익스플로러 처럼 디자인 바꿔 줬어요.

클릭 하세요.
Flex Gradient Explorer(플렉스 그라디언트 익스플로러)

신고
Posted by 째코
원리를 배운 곳:
http://www.quietlyscheming.com/blog/components/tutorial-displayshelf-component/
http://www.rictus.com/muchado/2006/07/05/live-reflection-component/



소스
Reflector.as
package
{
    import flash.display.BitmapData;
    import flash.display.GradientType;
    import flash.display.Graphics;
    import flash.display.Sprite;
    import flash.geom.Matrix;
    import flash.geom.Point;
   
    import mx.core.UIComponent;
    import mx.events.FlexEvent;
    import mx.events.MoveEvent;
    import mx.events.ResizeEvent;

    public class Reflector extends UIComponent
    {
        private var cachedBitmap:BitmapData;
        private var cachedMatrix:Matrix = new Matrix();
        private var tempPoint:Point = new Point();
        private var refresh:Boolean = true;
       
        public function Reflector() {
            super();
        }
       
        private var _target:UIComponent;
       
        [Bindable]
        public function get target():UIComponent {
            return _target;
        }
       
        public function set target(value:UIComponent):void {
            if(_target == value)
                return;
           
            if(_target != null) {
                _target.removeEventListener(ResizeEvent.RESIZE, target_resizeHandler);
                _target.removeEventListener(MoveEvent.MOVE, target_moveHandler);
                _target.removeEventListener(FlexEvent.UPDATE_COMPLETE, target_updateHandler, true);
                _target.parent.removeEventListener(FlexEvent.UPDATE_COMPLETE, target_updateHandler2, true);           
            }
           
            _target = value;
            _target.addEventListener(ResizeEvent.RESIZE, target_resizeHandler);
            _target.addEventListener(MoveEvent.MOVE, target_moveHandler);
            _target.addEventListener(FlexEvent.UPDATE_COMPLETE, target_updateHandler, true);
            _target.parent.addEventListener(FlexEvent.UPDATE_COMPLETE, target_updateHandler2, true);           
           
            refresh = true;
            invalidateDisplayList();
        }
       
        private var _falloff:Number = 1;
       
        [Bindable]
        public function get falloff():Number {
            return _falloff;
        }
       
        public function set falloff(value:Number):void {
            if(_falloff == value)
                return;
               
            _falloff = value;
            refresh = true;
            invalidateDisplayList();
        }
       
        private function target_resizeHandler(e:ResizeEvent):void {
            refresh = true;
           
            this.width = _target.width;
            this.height = _target.height;
           
            target_moveHandler(null);
        }

        private function target_moveHandler(e:MoveEvent):void {
            move(_target.x, _target.y + _target.height);
        }

        private function target_updateHandler(e:FlexEvent):void {
            refresh = true;
            invalidateDisplayList();
        }
       
        private function target_updateHandler2(e:FlexEvent):void {
            if(e.target == _target) {
                refresh = true;
                invalidateDisplayList();
            }
        }
       
        override protected function updateDisplayList(w:Number, h:Number):void {
            if(refresh) {
                refresh = false;
                refreshCache();
            }
           
            var g:Graphics = graphics;
            g.clear();
            g.beginBitmapFill(cachedBitmap, cachedMatrix);
            g.drawRect(0, 0, w, h);
        }
       
        protected function refreshCache():void {
            // 알파비트맵을 위한 것 으로써,
            // 1. createGradientBox() 를 이용해 그라디언트 방향을 90도로 바꾼다.
            // 2. beginGradientFill()과 drawRect() 를 이용해  1에서 0으로 점점 흐려지는 알파를 그린다.
            //    이때, 그려지는 컬러는 무엇이든 상관없다. 중요한 것은 해당 컬러에 대응하는 알파값이다.
            //    이유는 copyPixels() 에서 alphaBitmap이 사용될 때, 비트맵이 가지고 있는 컬러는 무시하고
            //    알파만 참조하기 때문이다.
            var gradientSprite:Sprite = new Sprite();
            var gradientMatrix:Matrix = new Matrix();
            gradientMatrix.createGradientBox(_target.width, _target.height*_falloff, Math.PI/2, 0, _target.height*(1-_falloff));
            gradientSprite.graphics.beginGradientFill(GradientType.LINEAR, [0xffffff, 0xffffff], [0, 1], [0, 255], gradientMatrix);
            gradientSprite.graphics.drawRect(0, _target.height*(1-_falloff), _target.width, _target.height*_falloff);
           
            // 위에서 만들어진 Sprite를 비트맵에 그린다.
            var alphaBitmap:BitmapData = new BitmapData(_target.width, _target.height, true, 0);
            alphaBitmap.draw(gradientSprite);
           
            // target 객체를 그린다.
            var targetBitmap:BitmapData = new BitmapData(_target.width, _target.height, true, 0);
            targetBitmap.draw(_target);
           
            // 타겟비트맵을 복사한다. 복사할 때, 맨처음 만든 알파비트맵을 옵션으로 넣어준다.
            // 알파비트맵으로 인해  투명하게 그라데이션 된다.
            cachedBitmap = new BitmapData(_target.width, _target.height, true, 0);
            cachedBitmap.copyPixels(targetBitmap, cachedBitmap.rect, tempPoint, alphaBitmap);
           
            // 매트릭스의 y축을 -1로 설정하여 반전 시킨후, 반전된 만큼 원래 위치로 잡기위해 y좌표를 수정한다.
            cachedMatrix.identity();
            cachedMatrix.scale(1, -1);
            cachedMatrix.translate(0, _target.height);
        }
    }
}

main.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
                xmlns:local="*"
                layout="absolute"
                backgroundColor="#000000" >
               
    <mx:Panel id="panel" x="10" y="10" width="337" height="102" layout="absolute" title="Reflection Panel" borderColor="#FDFF50">
        <mx:Label x="10" y="10" text="alpha"/>
        <mx:HSlider id="alphaSlider" x="54" y="10" width="253" minimum="0" maximum="1" liveDragging="true" value="1"/>
        <mx:Label x="9" y="36" text="falloff"/>
        <mx:HSlider id="falloffSlider" x="54" y="36" width="253" minimum="0" maximum="1" liveDragging="true" value="1"/>
    </mx:Panel>
    <local:Reflector target="{panel}" alpha="{alphaSlider.value}" falloff="{falloffSlider.value}"/>
   
</mx:Application>


신고
Posted by 째코
이 글은 Flex3 기준 입니다.

Container 클래스도 다른 컨트롤과 마찬가지로 UIComponent를 상속 받습니다.
Container 클래스를 상속받은 다양한 컨테이너들은 각각 나름대로의 방식으로 자식 컨트롤들을 배치 합니다.
만약 자식 컨트롤의 크기(width, hetight)가 변경된다면, 기본적으로 부모 컨테이너는 자식 컨트롤들을 자동으로 다시 배치 합니다. 이 때 만약 자식 컨트롤의 크기가 변경 되더라도, 부모 컨테이너가 자식 컨트롤들을 다시 배치하는 것을 막으려면 autoLayout 속성을 false로 설정 하면 됩니다. autoLayout 속성의 역할은 다음과 같습니다.

autoLayout
true일 경우, 자식의 크기가 변경되면 부모 컨테이너는 자식들을 다시 배치한다.
false일 경우, 자식이 추가되거나 제거될 때 단 한번만 자식들을 다시 배치한다.
디폴트로 true.

이 내용을 Flex SDK의 소스코드에서 확인해보면...
컴포넌트의 크기가 변경되었을 경우, 부모의 invalidate~() 메소드 2개를 호출하는 코드를 확인할 수 있습니다.
override public function set width(value:Number):void
{
    if (explicitWidth != value)
    {
        explicitWidth = value;

        // We invalidate size because locking in width
        // may change the measured height in flow-based components.
        invalidateSize();
    }

    if (_width != value)
    {
        invalidateProperties();
        invalidateDisplayList();

        var p:IInvalidating = parent as IInvalidating;
        if (p && includeInLayout)
        {
            p.invalidateSize();
            p.invalidateDisplayList();
        }

        _width = value;

        dispatchEvent(new Event("widthChanged"));
    }
}

그리고 자식의 크기가 변경되어 부모는 다시 배치를 시도하지만, autoLayout 속성에 따라 다시 배치할지 안할지를 경정하는 코드를 확인할 수 있습니다.
override public function validateDisplayList():void
{
    // trace(">>Container validateLayoutPhase " + this);
   
    var vm:EdgeMetrics;

    // If autoLayout is turned off and we haven't recently created or
    // destroyed any children, then don't do any layout
    if (_autoLayout || forceLayout)
    {
        doingLayout = true;
        super.validateDisplayList();
        doingLayout = false;
    }
    else
    {
         Layout borders, Panel headers, and other border chrome.
         layoutChrome(unscaledWidth, unscaledHeight);
     }
}
(forceLayout 속성은 autoLayout 속성이 false일 경우, 자식이 추가 되거나 제거될 때 사용되는 플래그 입니다.)

위 코드에서 autoLayout 속성이 true라면, validateDisplay() 메소드가 호출될 것이고, 그것에 의해서 결국updateDisplayList() 메소드가 호출됨으로써 자식 컨트롤을 다시 배치하게 됩니다. Container 클래스의 updateDisplayList() 메소드에서는 layoutChrome() 이라는 메소드를 호출하게 됩니다. 이것의 흐름을 정리해보면 다음과 같습니다.

(autoLayout == true) -> updateDisplayList() -> layoutChrome()

그리고 다시 위 코드를 보면 autoLayout 속성이 false일 경우 layoutChrome() 메소드만 별도로 호출하는 코드를 확인할 수 있습니다. 이것까지 합쳐 흐름을 다시 정리해보면 다음과 같습니다.

(autoLayout == true) -> updateDisplayList() -> layoutChrome()
(autoLayout != true) -> layoutChrome()

감 잡으셨나요? autoLayout 속성이 true이든 false이든 자식 컨트롤의 크기가 변경되면, 부모 컨테이너의layoutChrome() 메소드는 반드시 호출 됩니다. 이쯤에서 layoutChrome() 메소드의 역할을 알아보겠습니다.

layoutChrome()
컨테이너의 경계선을 정의한다.
Panel의 경우 layoutChrome() 메소드에서 경계선 및 타이틀바를 정의한다.

그렇다면 layoutChrome() 메소드는 왜 updateDisplayList() 메소드로부터 따로 독립 했을까요?
그 이유는 layoutChrome() 메소드의 역할 자체에 있습니다. 자식 컨트롤의 크기가 변경되었을 경우, autoLayout 속성에 상관없이 컨테이너의 경계선을 다시 그리기 위함 입니다.


※ 보너스 정보
absolute 형식의 레이아웃을 지원하는 컨테이너의 경우, 자식 컨트롤의 크기가 변경되었을 때 뿐만 아니라 좌표가 변경되었을 경우에도 자식 컨트롤을 다시 배치 합니다. 하지만 UIComponent의 좌표 속성(x, y)에는 자신만 변경을 하고, 부모 컨테이너의 invalidate~() 메소드를 호출하지 않습니다. 그럼에도 불구하고 자식의 좌표가 변경 되었는지 감지하는 이유는, 자식이 추가될때 Move 이벤트 리스너를 장착하기 때문 입니다. 이것은 absolute 형식의 레이아웃을 지원하는 컨테이너에만 해당하는 내용이며, 그 외의 모든 컨테이너는 크기가 변경되었을 경우만 자식들을 다시 배치 합니다.

신고
Posted by 째코
참조 : Adobe Flex3 실전 트레이닝 북, 국내 블로그, 해외 블로그
이 글은 어도비리아에 기술문서로 제출 되었으며, 동일한 내용을 어도비리아에서 볼 수 있습니다.


-1부 디버깅-
<목차>
1. 디버깅이란?
2. 디버깅의 종류
2-1. Trace()
2-2. <mx:TraceTarget />
2-3. Flex Debugging perspective
2-3-1. Debug view
2-3-2. Variables view
2-3-3. Expressions view
2-3-4. Breakpoints view
2-4.
flash.debugger.enterDebugger()
3. 맺음말


1. 디버깅이란?
프로그래머가 의도하지 않은 소프트웨어의 오작동을 버그라고 한다.
디버깅은 이러한 버그를 찾아내고 수정하는 것을 말하며,
소프트웨어의 품질을 향상 시키기위해 반드시 거쳐야 할 과정이다.

이 글에서 여러분은 Flex Builder에서 효과적으로 디버깅 하는 방법을 배울 것이며,
더 나아가 개발 습관에도 좋은 영향을 줄 것이다.


2. 디버깅의 종류
Flex에서 할 수 있는 디버깅은 크게 3가지가 있다.
- Trace()
- <mx:TraceTarget />
- Flex Debugging perspective
이 3가지 방법 모두 "특정한 시점에 객체가 가지고 있는 값" 을 확인하는 것에 초점을 둔다.
그럼으로써 프로그램이 의도한대로 동작하는지 알게 될 것이다.
그리고 이 중에서 Trace()와 <mx:TraceTarget /> 태그는 디버깅 보다는 로깅에 가깝다.
하지만 "특정한 시점에 객체가 가지고 있는 값" 을 확인하는 용도로써 훌륭한 디버깅 도구가 될 수 있다.

그럼 이제부터 이 3가지 종류에 대해 알아보도록 하겠다.

2-1. Trace()

프로그램의 특정 기능이 수행되는 동안 객체들이 의도한 값을 가지고 있는지 확인하고 싶을때
이 함수를 이용한다. 이 함수는 객체의 값을 콘솔에 출력해주는 역할을 한다.
프로그램의 흐름속에 Trace() 함수를 이용해 값을 확인 함으로써 프로그램이 정상적으로 작동 되는지
확인할 수 있을 것이다.

간단한 예제를 통해 사용법을 알아 보겠다.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
    creationComplete="creationComp()">
    <mx:Script>
        <![CDATA[
            import mx.utils.ObjectUtil;
            private function creationComp():void {
                var obj:Object = new Object();
                obj.a = "a";
                obj.b = "b";
               
                trace(ObjectUtil.toString(obj));
            }
        ]]>
    </mx:Script>
</mx:Application>

위 코드를 디버그 모드로 실행(F11 키 또는 벌레모양 아이콘
) 하면 콘솔에서 다음과 같은 결과를 확인할 수 있다.
(Object)#0
  a = "a"
  b = "b"

위 예제에서 사용한 ObjectUtil 클래스는 Trace() 함수와 함께 사용하면 매우 유용하다.
ObjectUtil.toString() 메서드는 객체가 가지고 있는 프로퍼티와 값을 출력결과 처럼 포맷해서 리턴해준다.

2-2. <mx:TraceTarget />
Flex 애플리케이션을 개발 하는데 있어 어려운 부분 중 하나는 서버와 통신하는 경우이다.
어떤 원인에 의해 서버로부터 기대했던 데이터를 받지 못할 경우 원인을 찾아내기가 힘들다.
이런 경우 <mx:TraceTarget /> 태그를 이용하면 원인을 쉽게 파악할 수 있다.
이 태그는 서버와 통신을 할 때 통신상태 및 전송되는 데이터를 콘솔에 출력해주는 역할을 한다.
단지 태그를 MXML 문서에 추가하기만 하면 콘솔에서 그 내용을 확인할 수 있다.

간단한 예제를 통해 사용법을 알아 보겠다.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">   

    <mx:TraceTarget />
   
    <mx:HTTPService id="http"
                               url="http://www.naver.com"
                               resultFormat="text" />
                   
    <mx:Button  label="click me"
                      click="http.send()" />
                               
</mx:Application>

위 코드를 디버그 모드로 실행(F11 키 또는 벌레모양 아이콘) 하면 콘솔에서 다음과 같은 결과를 확인할 수 있다.
mx.messaging.Producer '1D8D6911-2BBB-B851-5B2B-A2BA93C8F10A' producer set destination to 'DefaultHTTP'.
mx.messaging.Channel 'direct_http_channel' channel endpoint set to http:
mx.messaging.Producer '1D8D6911-2BBB-B851-5B2B-A2BA93C8F10A' producer sending message '54738616-39F6-E6DA-940C-A2BA98DFACB2'
mx.messaging.Channel 'direct_http_channel' channel sending message:
(mx.messaging.messages::HTTPRequestMessage)#0
  body = (Object)#1
  clientId = (null)
  contentType = "application/x-www-form-urlencoded"
  destination = "DefaultHTTP"
  headers = (Object)#2
  httpHeaders = (Object)#3
  messageId = "54738616-39F6-E6DA-940C-A2BA98DFACB2"
  method = "GET"
  recordHeaders = false
  timestamp = 0
  timeToLive = 0
  url = "http://www.naver.com"
mx.messaging.Producer '1D8D6911-2BBB-B851-5B2B-A2BA93C8F10A' producer connected.
mx.messaging.Producer '1D8D6911-2BBB-B851-5B2B-A2BA93C8F10A' producer acknowledge of '54738616-39F6-E6DA-940C-A2BA98DFACB2'.
mx.rpc.http.HTTPService Decoding HTTPService response
mx.rpc.http.HTTPService Processing HTTPService response message:
(mx.messaging.messages::AcknowledgeMessage)#0
  body = "결과 값 생략"
  clientId = "DirectHTTPChannel0"
  correlationId = "54738616-39F6-E6DA-940C-A2BA98DFACB2"
  destination = ""
  headers = (Object)#1
    DSStatusCode = 200
  messageId = "EC0ED47D-ABD2-8671-79ED-A2BA9950521B"
  timestamp = 0
  timeToLive = 0

위 결과에서 알 수 있듯이 전송상태 및 전송 데이터("결과 값 생략" 부분)를 쉽게 확인할 수 있다.
또한 이 태그는 디버깅 보다는 로깅과 매우 밀접한 연관이 있다.
하지만 이 글에서는 오직 디버깅의 용도로만 사용한 것이며 로깅에 관한 부분은 다루지 않는다.


2-3. Flex Debugging perspective
Flex Builder(Eclipse Platform, 이하 빌더) 에서 지원하는 디버깅으로써 이 글의 핵심이라고 할 수 있다.
개발자가 원하는 "특정한 시점"에 객체들의 상세한 값을 확인하고자 할 때 이 기능을 이용한다.
빌더에서 지원하는 디버깅 기능을 이용하면 애플리케이션을 일시 중지하고 중지된 상태의 시점에서
객체들의 상태를 확인할 수 있을 뿐만 아니라 한줄한줄 코드 실행을 제어할 수 있다.

그럼 실습을 통해 자세하게 알아보겠다.

빌더에서 지원하는 디버깅은 "특정한 시점" 으로부터 시작된다.
따라서 여러분은 먼저 객체의 값을 확인하고자 하는 "특정한 시점"을 정해야 한다.
먼저 소스뷰에서 특정 라인번호를 더블클릭 하면 다음 그림처럼 빨간색 박스친 부분의 점이 표시될 것이다.
그 점이 바로 "특정한 시점" 이며 애플리케이션이 중지되고 객체의 상태를 확인할 수 있는 지점이다.
빌더에서는 "특정한 시점"을  보다 전문적인 용어로 "브레이크 포인트" 라고 부른다.


이제 애플리케이션을 디버그 모드
(F11 키 또는 벌레모양 아이콘) 로 실행 시켜보자.
애플리케이션이 시작되면 초기화 과정(creationComplete 이벤트)에서 브레이크 포인트 지점의 코드가
수행된다.
브레이크 포인트 지점의 코드가 수행될 때 Flex Builder는 자동으로 디버깅 모드로 전환되고
애플리케이션은 정지상태가 된다.

디버깅 모드로 전환된 모습은 다음 그림과 같다.


①번 영역은 코드 실행을 제어하거나 세부적인 디버깅을 컨트롤할 때 사용하는 Debug view로 구성되어 있다.
②번 영역은 객체의 상세한 정보를 볼 수 있는 Variables view,
브레이크 포인트의 목록을 확인할 수 있는 Breakpoints view,
특정 변수를 주시하고 싶을때 사용하는 Expressions view 로 구성되어 있다.

그럼 이제부터 각각의 view에 대해 자세히 알아보겠다.

2-3-1. Debug view
애플리케이션이 브레이크 포인트를 만나서 디버깅 모드로 진입했을 때 애플리케이션을 디버깅을 중지하고 다시 실행시키거나 한줄한줄 코드를 실행하고자 할 때 Debug view를 사용한다.
Debug view에는 다음과 같이 디버깅을 제어할 수 있는 아이콘이 있다.

Resume

브레이크 포인트에 의해 애플리케이션이 정지상태가 되었을 때, 디버깅을 멈추고 정지된 애플리케이션을 이어서 가동시킨다. 만약 또 다른 브레이크 포인트를 만난다면 다시 디버깅 모드로 진입된다.

Suspend

애플리케이션과 함께 디버깅을 일시 중지한다.

Terminate

애플리케이션과 함께 디버깅을 종료한다.

Disconnect

Flex Builder의 디버거와 연결을 끊는다.
연결이 끊기면 브레이크 포인트를 만나더라도 디버깅 모드로 진입할 수 없다.

Step Into

현재 라인이 함수라면 함수 내부의 첫번째 라인으로 이동한다.
만약 현재 라인이 함수가 아니라면 현재 라인을 실행하고 다음 라인으로 이동한다.

Step Over

현재 라인을 실행하고 다음 라인으로 이동한다.

Step Return

현재 실행중인 함수를 호출한 부모함수로 이동한다.
예를들면, Step Into에서 함수 내부로 이동했을 경우 다시 밖으로 빠져 나오게 된다.


2-3-2. Variables view
애플리케이션이 브레이크 포인트를 만나 정지상태가 되었을 경우 정지된 시점에서의 객체들의 값을 확인할 때 Variables view를 이용한다.
다음 그림은 이번 장의 예제코드를 디버그 모드로 실행했을 때의 Variables view의 모습이다.

위 그림에서 this는 현재 브레이크 포인트가 위치한 클래스(또는 MXML문서) 이다.
트리의 노드 앞에 있는 아이콘은 해당 노드의 가시성을 나타낸다.
따라서 this 하위에 있는 a는 private, b는 protected, c는 public 가시성을 가지는 변수이다.
그리고 회색(L) 아이콘의 obj는 현재 수행중인 함수의 로컬변수임을 뜻한다.

this의 트리를 계속 열면 수백 개의 변수를 확인할 수 있으며, Ctrl+F 키나 마우스 우클릭후 Find Variable 메뉴를 통해 다음 그림처럼 특정 변수를 검색할 수 있다.

위 그림처럼 변수명을 입력하면 실시간으로 원하는 변수를 찾을 수 있다.


2-3-3. Expressions view
Variables view의 수많은 변수 중 특정한 변수를 주시하고 싶다면 Expressions view을 이용하면 된다.
Expressions view 는 특정 변수를 주시할 수 있고 변수들의 값을 원하는 형태의 결과로 볼 수 있는 기능을 제공한다.

먼저 예제 코드를 다음과 같이 변경하고 브레이크 포인트를 함수 종료부분에 지정하자.


코드를 변경 했다면 디버그 모드
(F11 키 또는 벌레모양 아이콘) 로 애플리케이션을 시작한다.
애플리케이션이 브레이크 포인트를 만나 디버깅 모드로 진입하면 Variables view에서  주시하고자 하는 변수에
마우스 우클릭후 Create Watch Expression 메뉴를 클릭한다.
이제 Expressions view를 확인해보면 다음 그림처럼 선택한 변수가 추가되어 있을 것이다.

이렇게 Expressions view에 변수를 추가해 놓으면 디버깅 하는 동안 Variables 창의 수많은 변수들 중 해당 변수를 찾을 필요 없이 바로 확인할 수 있다.

이번에는 Expressions view를 보다 효과적으로 사용하는 방법에 대해 알아보겠다.
먼저 Expressions
view에서 마우스 우클릭후 Add Watch Expression 메뉴를 클릭한다.
그리고 다음 그림처럼 변수들을 사칙연산으로 표현해보자.


OK 버튼을 누르고 Expressions
view를 확인해보면 다음 그림처럼 보일 것이다.


이처럼 Expressions
view에서는 특정 변수를 주시할 수 있을 뿐만 아니라 변수들의 연산까지 지원해서
변수들의 상호작용에 대한 결과를 바로 알 수 있다.

2-3-4. Breakpoints view
브레이크 포인트를 여기저기 지정하고 해당 문서를 닫았을 경우 지정한 브레이크 포인트들을 찾는 것은 쉬운일이 아니다. 이럴 때 Breakpoints view를 사용하면 지정한 브레이크 포인트들을 쉽게 찾을 수 있다.

다음 그림을 살펴보자.

이처럼 Breakpoints view에는 지정한 브레이크 포인트들의 리스트가 보여진다.
그리고 Delete키 또는 마우스 우클릭후 Remove메뉴를 통해 브레이크 포인트를 바로 제거할 수 있다.

2-4. flash.debugger.enterDebugger()
브레이크 포인트는 빌더에서 관리되기 때문에 브레이크 포인트 자체를 소스코드와 함께 공유할 수는 없다.
그러나 브레이크 포인트와 똑같은 기능을 수행하는 함수가 있다.
바로 flash.debugger.enterDebugger() 함수이다.
이 함수는 브레이크 포인트와 똑같은 기능을 수행하기 때문에 소스코드와 함께 디버깅 지점을 공유할 수 있다.

다음 그림을 보자.

디버깅 지점을 소스코드로 명시했기 때문에 Breakpoints view에 나타나지 않는다.
하지만 그 외에 브레이크 포인트와 다른 점은 없다.


3. 맺음말
지금까지 디버깅에 대해서 알아봤다.
앞으로는 이 글에서 소개한 디버깅 방법으로 소프트웨어 품질을 향상시키는데 노력하자.
마지막으로 디버깅은 개발이 끝난 이후에 하는 것이 아니라 개발과정의 일부분 이라는 것을 명심해야 한다.
신고

'Flex/Air' 카테고리의 다른 글

Flex4 SDK beta review  (2) 2009.07.03
Flex Builder에서 디버깅&프로파일링 하기 -2부-  (9) 2009.05.25
Flex Builder에서 디버깅&프로파일링 하기 -1부-  (0) 2009.04.20
AirMusic  (10) 2009.03.31
WebUtil Framework  (2) 2008.05.08
퍼즐  (0) 2008.04.26
Posted by 째코


티스토리 툴바