티스토리 툴바

블로그 이미지
"변화의 시기에는 배우려고 하는 이들이 세상을 차지합니다"

카테고리

분류 전체보기 (386)
매쉬업 (23)
Flash Platform (131)
AJIT (8)
Mobile (5)
JAVASCRIPT (33)
OpenAPI (5)
RIA (10)
Front-End (2)
Back-End (16)
SQL (2)
낙서장 (137)
TOOLs (4)
Total226,656
Today55
Yesterday86
Statistics Graph
가끔 이벤트 핸들러에 인자 값을 전달한다던지, 특정 횟수 만큼 호출되고 나면, 삭제를 해야 한다던지 할 경우가 있지요..
그런 이유로 다들 EventUtil 하나 정도는 가지고 계실 것 같은데요 ^^;

잉여 돋는 시간에 프레임워크를 만들고 있는데, 그 중 일부인 소스 공유합니다.
사용 방법은 주석에 써놨습니다~ ^^

다들 즐거운 하루 되세용~

package actionwire.util
{
	
import flash.events.Event;
import flash.events.IEventDispatcher;
import flash.utils.Dictionary;

/**
 * 
 * @author lovedev
 * @example 사용 예
 *  
 *  var sp:Sprite = new Sprite();
 *  EventProxy.addEventListener(sp, Event.SELECT_ALL, function($e:Event, $test:String):void
 *  {
 *	trace($test);
 *  },1,"testMessage AAA");
 *	
 *  var fn:Function = function($e:Event, $test:String):void
 *	{
 *		trace($test);
 *	};
 * 	
 *	EventProxy.addEventListener(sp, Event.SELECT_ALL, fn,0,"TestMessage BBB");
 *	
 *	sp.dispatchEvent(new Event(Event.SELECT_ALL));
 *	EventProxy.removeEventListener(sp, Event.SELECT_ALL, fn);
 *	sp.dispatchEvent(new Event(Event.SELECT_ALL));
 * 
 * //output
 * //testMessage AAA 
 * //TestMessage BBB
 * 
 * -----------------------------------------------------------------------------------
 * //이벤트 dispatch는 2번 되었지만
 * //테스트 메시지 AAA를 찍는 핸들러는 1회 호출 후 자동 remove 되었으며, 
 * //테스트 메시지 BBB를 찍는 핸들러는 강제 remove되어 핸들러가 호출되지 않는다.
 * -----------------------------------------------------------------------------------
 * 
 * 
 */	
public class EventProxy
{
	
	private static var _eventList:Dictionary = new Dictionary();
	
	/**
	 * 이벤트 발생이 가능한 객체에 이벤트를 등록합니다.
	 * @param $target 이벤트 발생 객체
	 * @param $eventType 이벤트 타입
	 * @param $listener 이벤트 핸들러
	 * @param $limitCount 
	 * 

호출 제한 카운트 지정 0일 경우 무제한 지정되었을 경우, * 지정된 수만큼 반복후 remove

* @param $rest 핸들러에 전달될 인자 * */ public static function addEventListener( $target:IEventDispatcher, $eventType:String, $listener:Function, $limitCount:uint = 0, ...$rest):void { if(!_eventList[$target]) _eventList[$target] = {}; if(!_eventList[$target][$eventType]) _eventList[$target][$eventType] = []; _eventList[$target][$eventType].push({ "listener" : $listener, "args" : $rest, "limitCount" : $limitCount, "executeCount" : 0 }); if(_eventList[$target][$eventType].length == 1) $target.addEventListener($eventType, onProxyDispatchEvent); } /** * * @param $e * */ private static function onProxyDispatchEvent($e:Event):void { var target:IEventDispatcher = $e.currentTarget as IEventDispatcher; var eventType:String = $e.type; if(_eventList[target].hasOwnProperty(eventType) && _eventList[target][eventType].length > 0) { var listener:Function, args:Array, limitCount:uint, idx:String, eventInfo:Object; var removableListener:Array = []; for(idx in _eventList[target][eventType]) { eventInfo = _eventList[target][eventType][idx]; listener = eventInfo.listener; args = eventInfo.args; if(!(args[0] is Event)) args.unshift($e); listener.apply(target, args); eventInfo.executeCount++; if(eventInfo.limitCount > 0 && eventInfo.limitCount <= eventInfo.executeCount) { removableListener.push(eventInfo); } } for each (eventInfo in removableListener) removeEventListener(target, eventType, eventInfo.listener); listener = null; args = null; idx = null; eventInfo = null; removableListener = null; } } /** * EventProxy를 통해 생성된 이벤트를 제거합니다. * @param $target * @param $eventType * @param $listener * */ public static function removeEventListener( $target:IEventDispatcher, $eventType:String = null, $listener:Function = null):void { //Case 1 if($eventType === null && $listener === null) { for(var eventType:String in _eventList[$target]) { $target.removeEventListener(eventType, onProxyDispatchEvent); } delete _eventList[$target]; return; } //Case 2 if($eventType !== null && $listener === null && _eventList[$target].hasOwnProperty($eventType)) { $target.removeEventListener($eventType, onProxyDispatchEvent); delete _eventList[$target][$eventType]; return; } //Case 3 if($eventType !== null && $listener !== null && _eventList[$target].hasOwnProperty($eventType)) { for(var idx:String in _eventList[$target][$eventType]) { if(_eventList[$target][$eventType][idx].listener === $listener) { _eventList[$target][$eventType][idx] = null; _eventList[$target][$eventType].splice(int(idx), 1); break; } } if(_eventList[$target][$eventType].length == 0) { $target.removeEventListener($eventType, onProxyDispatchEvent); delete _eventList[$target][$eventType]; } } } } }
저작자 표시 비영리 동일 조건 변경 허락
Posted by lovedev

Trackback | http://lovedev.tistory.com/trackback/621 관련글 쓰기

댓글을 달아 주세요

  1. 2011/02/18 12:06 Favicon of http://diebuster.com BlogIcon hika  댓글주소  수정/삭제  댓글쓰기

    처음으로 댓글을 남겨봅니다(처음부터 이런 글이냐..)
    위에서 언급하신 것처럼 이벤트 관련으로 다들 비슷한 생각들을 해보셨을거라 대동소이한 소스를 갖고 있어요 ^^
    단지 개인적인 의견을 말씀드리자면(이제부터 시작..)
    매번 unshift로 이벤트를 삽입하는 건 좀 지양해야할 거 같고,
    실무상 rest 외에도 외부 파일로부터의 입력이나 기존 배열로부터의 입력도 잦기 때문에 배열을 인자로 받는 시그니처도 같이 제공해 주시면 더 좋을거 같고,
    hasown도 느리니까 안쓰고 걍 대괄호 두 번으로 대체했으면 좋겠고,
    길이체크도 리무브로직을 믿으신다면 안했으면 좋겠지만..
    이런 건 다 게임만드는 입장이라 기저프레임웍이 호출되는 횟수를 고려했을 때 성능에 대한 주관적인 견해이고,

    진짜 의견은..

    매번 커스텀 정보를 오브젝트를 생성해서 넣을거면 걍 실드클래스를 자료전용으로 선언해서 차라리 그 클래스의 인스턴스를 생성하고 디스패치시에도 해당 인스턴스의 메소드를 호출하도록 중앙 스태틱에서 알고리즘을 이사시킬 것과,
    이를 통해 배열을 각 딕셔너리의 컨테이너로 쓰시던걸 벡터로 전환하심이 어떨까하는거죠.

    결국 분명히 더 추가되거든요.

    지금 도입하신 리미트체크기능 외에도 수 많은 커스텀 확장 기능이....
    그 때마다 이벤트 처리기 본체를 건드리는 것보단 역시 개별 이벤트보관클래스를 수정하는 편이 안전하니까..^^

    머 개인적인 사견이었습니당.

    • 2011/02/18 10:44 Favicon of http://lovedev.tistory.com BlogIcon lovedev  댓글주소  수정/삭제

      와~~ 엄청난!! 댓글이어요~~

      이건 프레임워크의 일부 유틸이에요. ^^
      잉여 시간에 만든 건데. 이것의 포인트는

      dispatch를 Reflection시킨다기 보다는
      eventType이 같을 경우 addEventListener는 1번밖에 안된다는 것이겠지요 ^^; 물론 이벤트 전파 과정에 대한 생리 주기를 제한적으로 타는 것이 단점이에요.

      priority같은 우선 순위나 버블 개념이겠지요..

      이 외에 Vector로 할 경우, Key 인덱싱 시간이 더 들 것 같습니다. 배열의 단점이잖아요.. 또한 9기준으로 했을 때, 호환성 측면에서는 Vector는 안쓰는게;;

      말씀하신 것처럼, Custom Object보다 클래스로 가는게 빠르고 좋아요~ ^^)/ 맞아요~

      그냥 30분 정도 생각하면서 프로토타입 삼아 만든거라.. 세밀한 부분까지 적용하지 않은 것으로 받아 들여 주세오.. 무섭네요~ ^^;;;

      rest외 배열로 인자를 받는 거 좋네요 ^^);;

      Dictionary로 리스트를 잡은 것은 외부에서 GC되어 객체가 사라질 경우, 이벤트의 키값도 저절로 사라지도록 한 거라 봐주셔요~
      Object를 키로 삼기 좋아서요.. 물론 Dictionary객체가 느리긴 하죠. ^^

      첨부적으로 말씀 드리지만,
      이벤트로직에 의한 통신으로 프레임워크는 움직이지 않습니다. 프레임워크는 프로토콜을 설계해야지요~

      이벤트로 커뮤니케이션을 제어하는 것은 느리고 한계도 많아요..

      이벤트보다 더 LOW레벨에서 지정된 프로토콜로 통신을 하게 됩니다.

      그냥.. 간단히 프레임워크에서 이벤트를 써야할 때, Refelection하려고 유틸성으로 넣은 거에요~

      사려깊은 댓글 무한 감사드립니다!!

  2. 2011/02/18 12:11 Favicon of http://diebuster.com BlogIcon hika  댓글주소  수정/삭제  댓글쓰기

    if(!_eventList[$target][$eventType]){
    _eventList[$target][$eventType] = [];
    벡터를 도입하자는건 이부분의 배열로 중앙컨테이너인 딕셔너리를 대체하자는건 아니었습니다 ^^;

    참고로 혹시 각 인스턴스가 브레이크로 찍어보면 @@로 시작하는 유일한 식별키를 갖고 있잖아요. 그것좀 추출하는 메서드가 있을까요 ^^; 모든 as3인의 열망 객체 id얻기를 성공시켰나 궁금합니다.

    • 2011/02/18 15:30 Favicon of http://lovedev.tistory.com BlogIcon lovedev  댓글주소  수정/삭제

      프로파일러는 만들어 봤는데.. 객체의 고유 아이디 찾아 본다는 생각은 안해봤네요..

      Sampler로 얻어진 ID가 객체의 원래 아이디로 알고 있어서 이 부분을 테스트 해봤더니.. 아니더군요.

      그래서 수단과 방법을 가리지 않고 아이디를 알아내긴 했는데요..

      근데 이게 왜 필요한건지가 좀 ^^;;
      객체 비교할 때 속도 측면?
      바보 된거 같아여;;;

      어디에 필요한지 알려 주시면~ 포스팅 하겠습니다. ^^;(용도가 궁금해서요;;;)
      정답은 아니겠지만.. 찾아지긴 하네요..

  3. 2011/02/18 16:55 Favicon of http://diebuster.com BlogIcon hika  댓글주소  수정/삭제  댓글쓰기

    원래 llvm이 가상머신에 개별 힙메모리 에뮬레이션으로 객체를 올릴때 숫자로 고유한 키를 부여해요. 자바에서는 최상위의 Object에 hash를 얻을수 있게 되어있잖아요.
    만약 디버깅시에 찍히는 고유한 인스턴스 id를 알 수 있으면 객체를 키로 잡는 컨테이너로 더이상 Dictionary를 쓸 필요가 없이 배열이나 벡터등의 숫자 인덱스 기반으로 이사갈 수 있게 되잖아요. 그 외에도 인스턴스 자체를 식별한 전역 키가 있으니까 객체 레퍼런스를 인자로 보내지 않고 프리머티브를 보낼 수도 있죠. 예를들어

    function setPosition( $target:DisplayObject, $x:Number, $y:Number ):void

    이런 함수를 생각해보면 만약 인스턴스 고유키를 알아낼 수 있다면,

    function setPosition( $targetId:String, $x:Number, $y:Number ):void{
    var target:DisplayObject = getObjectById( $targetId );
    ...
    이렇게 바꿀 수 있으니까 외부 설정으로 빼기도 좋고, 의존성도 현저하게 낮아지는 효과가...

    물론 Dictionary의 경우도 대부분 이용목적이 객체 자체를 키로 잡기 위해서인데 이게 결국 내부적으로는 객체의 해쉬키를 문자열로 해서 키로잡도록 어셈블리되거든요.

    var s:Shape = new Shape
    var d:Dictionary = new Dictionary;
    d[s] = 3;
    이렇게 되면 객체키를 잡는건 유저가 그렇게 느끼는거고, 사실은 s의 해쉬키를 문자열로 해서 Dictionary가 잡아준거잖아요. 짜피 고유한 숫자아이디를 얻을 수 있다면


    var s:Shape = new Shape
    var v:Vector.<Shape> = new Vector.<Shape>();
    v[getHashKey( s )] = 3;

    이렇게 바꿀 수 있으니까..일단 객체키를 잡으면 그게 안되는 언어도 많아서 크로스하게 소스를 쓸 수도 없고 나쁘다는..

  4. 2011/02/19 09:59 Favicon of http://sewonist.com BlogIcon sewonist  댓글주소  수정/삭제  댓글쓰기

    우오~ -0- 이렇게 이벤트 관리하는 법도 있군요. 라고 리플 달려고 보니 이건 뭐... 신들의 대화;;;;;;
    글 하나하나 모두 엄청 나네요. 본문의 소스를 30분 만에 작성하신 lovedev 님 도 정말 대단하십니다. 역시 ACC ^^
    구현 방법적인 면은 계속 디벨롭 될 수 있겠죠. 그런걸 떠나서 아이디어 자체가 너무 신기합니다.
    생각도 못해봤다는.. 큰 영감 받고 갑니다.

    • 2011/02/19 20:11 Favicon of http://lovedev.tistory.com BlogIcon lovedev  댓글주소  수정/삭제

      네네 그대로 쓰지 말고!! 보완해서 쓰셔요!! 그래야 발전의 발전을 거듭할 수 있고, 공개하는 의미도 있을 것 같아요! 좋게 봐주셔서 그저 감사할 따름이어요~ ^^;

      개선하면 트랙백이라도 걸어 주세요~ ^^
      감사합니다!

최근에 달린 댓글

최근에 받은 트랙백

달력

« » 2012.05
    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    

글 보관함