scaleform.minarto.com

Actionscript 만으로 DataBinding 을 구현해보자 1 본문

Communication

Actionscript 만으로 DataBinding 을 구현해보자 1

미나토 2012. 9. 27. 12:34


http://scaleform.minarto.com/365 에서 이어집니다



사용법은 기존의 scaleform.clik.data.DataBinding 의 용법과 똑같이 만들었습니다.




바로 코드를 보시겠습니다.



1. DataBindingX



package {
	import flash.external.ExternalInterface;
	import flash.utils.Dictionary;
	
	public class DataBindingX {
		private static var _dictionary:* = {};
		
		public static function initialize():void {
			ExternalInterface.call("DataBindingX ", DataBindingX );
		}
		
		public static function createBinding($key:String, $handler:Function):void {
			var t:* = _dictionary[$key];
			
			if (t) $handler(t.value);
			else t = _dictionary[$key] = { dic:new Dictionary(true) };
			
			t.dic[$handler] = $handler;
		}
		
		public static function deleteBinding($key:String, $handler:Function):void {
			var t:* = _dictionary[key];
			if(t) delete t.dic[$handler];
		}
		
		public static function setValue($key:String, $value:*):void {
			var t:* = _dictionary[$key];
			
			if (t) {
				if (t.value == $value) return;
				
				t.value = $value;
				
				var d:Dictionary = t.dic;
				for (t in d) d[t]($value);
			}
			else _dictionary[$key] = { dic:new Dictionary(true), value:$value };
		}
	}	
}


일단 8번 라인의 initialize 함수를 실행하면 클라에게 이 클래스의 포인터를 던지게 되겠죠... 클라이언트는 다른 위젯의 initialize 를 실행했을 때 포인터를 받듯 받아놓고선 api를 실행하면 됩니다




2. createBinding




		public static function createBinding($key:String, $handler:Function):void {
			var t:* = _dictionary[$key];
			
			if (t) $handler(t.value);
			else t = _dictionary[$key] = { dic:new Dictionary(true) };
			
			t.dic[$handler] = $handler;
		}





12번 라인의 createBinding 함수를 보겠습니다.


들어온 키값이 있는지 _dictionary 에서 찾습니다.


없다면 오브젝트를 하나 만듭니다. 그 오브젝트에는 dic 이라는 키값을 가진 Dictionary 객체가 있고, 지금은 안보이지만 value 라는 값을 저장하는 곳이 있습니다.

(Dictionary : http://help.adobe.com/ko_KR/FlashPlatform/reference/actionscript/3/flash/utils/Dictionary.html)


그렇게 만들어놓은 Dictionary 객체에 핸들러를 등록합니다.



만약 이미 만들어진 객체가 있다면 객체안에 들어있던 value 값을 인자로 넣어서 핸들러를 실행하고, 핸들러를  Dictionary 객체에 등록합니다.





3. setValue



자, 이번에는 클라이언트가 사용하게 될 setValue 함수입니다


		public static function setValue($key:String, $value:*):void {
			var t:* = _dictionary[$key];
			
			if (t) {
				if (t.value == $value) return;
				
				t.value = $value;
				
				var d:Dictionary = t.dic;
				for (t in d) d[t]($value);
			}
			else _dictionary[$key] = { dic:new Dictionary(true), value:$value };
		}


마찬가지로 key라는 인자를 첫번째로 받고, 두번째 해당하는 값을 인자로 받습니다


일단 해당 키값이 있는지 찾습니다.


없다면 해당 키값에 대한 오브젝트를 생성합니다. 앞서서 createBinding 에서 생성하는 것과 달라진게 있다면 이번에는 값이 같이 들어왔으니 value 라는 키값으로 값또한 저장합니다.

createBinding 에서 핸들러를 실행할 때 가져다 쓴 값이 바로 이 값이죠...



만약 이미 오브젝트가 있다면 일단 값이 기존 값과 다른지부터 검사합니다. 값이 같다면 또 핸들러를 실행할 필요가 없을테니까요... 괜히 퍼포먼스를 저하시킬 필요가 없답니다.


값이 기존 값과 다르다면 값을 저장합니다.


그리고 dic이라는 Dictionary 객체에 등록되어 있던 모든 핸들러를 실행시킵니다. 물론 해당 값을 인자로 넣어서요.



deleteBinding 은 당연히 바인딩을 해제하는 겁니다. 굳이 따로 설명하지 않겠습니다.




4. 사용법



너무나 간단합니다.


UI 개발자는 기존 DataBinding 과 똑같이 바인딩을 겁니다.

예를 들어서 메인 캐릭터가 가진 돈을 바인딩 건다고 치죠... 그럼 다음과 같이 코드를 작성하면 됩니다.



package  {
	import flash.text.TextField;
	
	import scaleform.clik.core.UIComponent;
	import DataBindingX;
	
	
	public class TestWidget extends UIComponent {
		public var textField:TextField;

		override protected function configUI():void {
			super.configUI();
			
			DataBindingX.initialize();
			DataBindingX.createBinding("mc.money", onChangedMoney);
		}
		
		
		private function onChangedMoney($money:Number):void{
			textField.text = "" + $money;
		}
	}
}


물론 초기화는 어디서건 한번만 하면 되니 이 코드에서는 필요없을 수도 있습니다.




클라이언트는 initialize 시에 받은 DataBindingX 포인터를 통해서 setValue 인보크 함수를 실행해주면 되겠죠?





5. 장점



일단 제가 만든 DataBinding 의 장점으로는 



1. 극도로 적은 인보크 함수 실행


기존의 DataBinding 은 UI 쪽의 함수 포인터를 클라이언트 측에 저장해놓고선 클라이언트가 값이 변경될 때마다, 등록된 함수들을 일괄 실행하게 됩니다.


그러면 그 바인딩된 함수 갯수만큼의 인보크 호출이 일어납니다. 하지만 이 방식은 해당하는 값이 변경되는 한번만 실행합니다.




2. 값의 일괄적인 가공을 한 후 실행


예를 들어서 setValue 설명에서 봤듯이 새로 들어온 값을 기존 값과 비교한 후 실행합니다. 그러니 불필요한 함수 실행을 원천적으로 막아버립니다.

물론 이건 기존의 방식에서도 쓸 수 있겠죠...



직접 UI 개발자가 돈에 자릿수 콤마를 찍어서 바인딩을 걸 수도 있겠죠.  그럼 각 핸들러에서 따로 해당 기능을 적용하는 것보다도 훨씬 효율적입니다.




3. DataBinding 을 클라이언트가 구현할 필요가 없습니다.


예를 들어 UDK 에는 DataBinding 이 적용되어 있지 않습니다. 그렇기 때문에 클라이언트가 DataBinding 을 적용하려면 해당 코드를 구현해줘야 합니다.


하지만 이건 UI 내부에서 구현해버렸으니, 클라이언트에서는 기존에 하던대로 인보크 함수를 실행하면 됩니다.



4. UI 개발자가 직접 바인딩 값 변경을 할 수도 있다


기존에는 클라이언트만이 값을 변경하여 테스트할 수 있었습니다.


하지만 UI 개발자가 값을 변경해야 할 때도 있습니다.

아마 테스트 용으로도 사용가능할 거고요... 다른 용도도 있겠죠???




6. 단점



1. 퍼포먼스


기존 DataBinding 에서 클라이언트가 하던 것을 UI 가 하는 겁니다. 키값을 찾는다던가 핸들러들을 실행시키는 것이라던가 하는 실행 속도는 분명 떨어질겁니다.


만약 바인딩을 걸고 걸어서 수백개의 바인딩이 생긴다면...


여기까지는 저도 실 테스트를 해보질 않아서 모르겠습니다...



하지만 통신이 줄어들었기 때문에 아직 전체적인 퍼포먼스가 떨어진다고는 하기 힘드네요...

아직 단점인지 알 수 없습니다.