http://www.kirupa.com/forum/showthread.php?p=1934869#post1934869
http://www.kirupa.com/forum/showthread.php?p=1934887#post1934887
http://www.kirupa.com/forum/showthread.php?p=1939920#post1939920
http://www.kirupa.com/forum/showthread.php?p=1961524#post1961524

────────────────────────────────────

액션스크립트 1과 액션스크립트 2의 addProperty 메서드, 객체를 위한 __resolve 핸들러의 입지를 대신하기 위해 액션스크립트 3에는 Proxy 클래스(flash.utils.Proxy)가 새로 도입되었습니다.

액션스크립트 1과 액션스크립트 2에서
  • addProperty() - 객체 또는 클래스를 위한 getter/setter 속성을 동적으로 사용하기 위해 사용됩니다. 이것은 addProperty 호출에 넘겨진 함수를 통해 값을 얻고 설정하는 변수를 동적으로 생성합니다.
  • __resolve - 객체를 위해 정의될 경우, 객체에 존재하지 않는 속성 또는 메서드를 호출할 때 호출되는 핸들러입니다. 이것은 객체에 대한 해석되지 않는 참조를 포착하고 적절히 대응할 수 있게 합니다.


액션스크립트 3에서는 Proxy 클래스의 모든 특성의 이점을 얻기 위해 Proxy를 확장하는 클래스를 생성합니다, 다음을 포함합니다.

  • 속성(property) 설정 포착하기
  • 속성(property) 접근 포착하기
  • 속성(property) 검사 포착하기 (존재한다면)
  • 속성(property) 제거 포착하기
  • 메서드 호출 포착하기
  • 자손 접근 포착하기
  • 속성(attribute) 검사 포착하기
  • 속성(property) 열거 처리하기

property는 일반 객체의 속성을, attribute는 XML 구조에서의 그 속성을 말합니다.

이 특성들이 AS1과 AS2에서 사용할 수 있던 많은 이점들을 수용한다 하더라도, Proxy를 사용하는데는 몇 가지 결점이 있습니다:

  • 클래스가 Proxy를 확장해야 하기 때문에 인스턴스 타입이 제한되고, 그러므로 인터페이스에 의존해야 합니다.
  • Proxy를 상속하지 않는 클래스를 상속하는 Proxy 서브클래스를 만들 수 없습니다.
  • 표시 객체는 Proxy 클래스가 될 수 없습니다.


일반적으로 Proxy 클래스는 특별한 유연성이 필요한 변수 컨테이너 클래스를 위해 사용합니다.

Proxy 클래스는 나중의 팁에서 더 자세하게 다룰 것입니다

──────────────────────────────────────────

getProperty와 setProperty는 속성 접근을 관리하기 위해 Proxy 클래스에서 사용되는 메서드입니다. 프록시 인스턴스 안에서 정의되지 않은 속성에 접근할 때, 그것에 접근하기 위해 getProperty가 호출됩니다. 설정할 때, 그것을 설정하기 위해 setProperty가 호출됩니다.

Proxy 클래스의 모든 메서드가 그렇듯이, public과의 충돌을 막기 위해 getProperty와 setProperty는 flash_proxy 네임스페이스 안에 정의됩니다. 당신의 Proxy 서브클래스 안에서 이 메서드들을 재정의할 때, 당신은 반드시 flash_proxy 네임스페이스를 사용해야 합니다.

다음 예제 CustomObject는 Proxy를 확장하고, 자신의 인스턴스를 위한 동적 속성 설정 관리를 위해 getProperty와 setProperty를 사용합니다.

ActionScript Code:
package {
   
    import flash.utils.Proxy;
    import flash.utils.flash_proxy;
   
    dynamic public class CustomObject extends Proxy {
       
        public var classProperty:String = "classProperty"; // generic class variable
        private var customProperties:Object = new Object(); // store custom variables
       
        public function CustomObject() {
        }
       
        // called when getting dynamic variables
        override flash_proxy function getProperty(name:*):* {
            if (name in customProperties) {
                return customProperties[name];
            }
            return "Property does not exist";
        }
        // called when setting dynamic variables
        override flash_proxy function setProperty(name:*, value:*):void {
            customProperties[name] = "Property "+name+": "+value;
        }
    }
}


 

ActionScript Code:
// usage example
var myObj:CustomObject = new CustomObject();
trace(myObj.foo); // Property does not exist
myObj.foo = "bar";
trace(myObj.foo); // Property foo: bar

trace(myObj.classProperty); // classProperty
myObj.classProperty = "bar";
trace(myObj.classProperty); // bar
 


foo 속성에 접근하고 설정할 때, 클래스를 위해 정의된 customProperties 안에 저장된 foo의 근본적인 값을 제어하기 위해 getProperty와 setProperty가 사용된다는 것을 숙지하세요. 또한, classProperty가 dynamic 변수가 아니므로, 클래스를 위해 정의한 변수가 되는 대신, getProperty와 setProperty가 적용됩니다.

───────────────────────────────────────────────

Proxy 클래스의 callProperty 메서드는 Proxy 인스턴스에서 호출된 메서드를 위한 행동을 정의할 수 있게 해줍니다. 프록시 인스턴스 안에서 정의되지 않은 메서드를 호출할 때, 호출한 메서드의 이름과 사용된 인수들의 배열이 넘겨진 callProperty가 실행됩니다.

Proxy 클래스의 모든 메서드가 그렇듯이, callProperty는 public과의 충돌을 막기 위해 flash_proxy 네임스페이스(flash.utils.flash_proxy)에 정의되어 있습니다. 당신의 Proxy 서브클래스에서 이 메서드들을 재정의할 때, flash_proxy 네임스페이스를 사용해야 합니다.

다음 예제 CustomObject는 Proxy를 확장하고 자신의 인스턴스에 대해 호출한 동적 메서드를 관리하기 위해 callProperty를 사용합니다.

ActionScript Code:
package {
   
    import flash.utils.Proxy;
    import flash.utils.flash_proxy;
   
    dynamic public class CustomObject extends Proxy {
       
        private var variables:Object = new Object(); // stores variables
       
        public function CustomObject() {
        }
       
        // called when calling dynamic methods
        override flash_proxy function callProperty(name:*, ... args):* {
           
            // convert name into string
            name = String(name);
           
            var callType:String = name.slice(0,3); // get or set
            var callVariable:String = name.slice(3); // variable name behind get or set
           
            switch(callType) {
               
                case 'get':
                    // if get, get from variables object if exists
                    if (callVariable in variables) {
                        return variables[callVariable];
                    }
                    return null;
                   
                case 'set':
                    // if set assign to variables object
                    variables[callVariable] = args[0];
            }
        }
    }
}


이 예제는 variables 객체에 저장되는 동적 "변수들" 을 얻고 설정하기 위한 범용적인 get/set 방법을 받아들이기 위해 callProperty를 사용합니다.

ActionScript Code:
// usage example
var myObj:CustomObject = new CustomObject();
trace(myObj.getMyVar()); // null
myObj.setMyVar("foo");
trace(myObj.getMyVar()); // foo
myObj.setMyVar("bar");
trace(myObj.getMyVar()); // bar
trace(myObj.MyVar); // doesnt exist (get property error)
 


아직 (setMyVar를 이용해서) "MyVar" 를 설정하지 않았으므로 첫번째 getMyVar는 null을 반환합니다. 설정한 후, getMyVar는 값을 반환합니다.

───────────────────────────────────────────

setProperty와 callProperty의 경우처럼, Proxy (flash.utils.Proxy) 인스턴스의 동적 성질로, 클래스 메서드를 사용하여 Proxy 인스턴스 열거(enumeration)를 제어할 수 있습니다(for..in과 for each..in을 사용하여 Proxy 인스턴스의 속성들에 대해 루프를 돌립니다). 이 일을 하는 메서드들은:

  • nextName(index:int):String
  • nextValue(index:int):*
  • nextNameIndex(index:int):int

nextName과 nextValue 둘 다 for..in 또는 for each..in 루프에서 다음에 올 것을 결정할 수 있게 해주는 함수입니다(nextName은 for..in 루프와 관련있고 nextValue는 for each..in과 관련있습니다). nextName이 반환하는 값은 for..in에서 주는 키(key)이고 nextValue가 반환하는 값은 for each..in을 위한 값입니다. 이것들의 호출에서 index 인수는 nextNameIndex가 만들어내는 숫자입니다.

nextNameIndex는 각 루프 반복 전에 호출되고 다음 두 일을 할 수 있게 합니다: a) nextName과 nextValue (그리고 다음 호출을 위해 자기 자신)에서 접근하는 인덱스 값, 또는 b) 루프를 중지합니다. 둘 다 nextNameIndex의 반환값에 의해 지시됩니다. 현재 루프 반복을 위해 0이 아닌 정수가 사용되고, nextNameIndex 바로 다음 호출되는 nextName 또는 nextValue에 넘겨집니다. 0은 nextNameIndex 후의 루프를 중지하고 인스턴스에 대해 사용되는 for..in 또는 for each..in 블록을 종료합니다. nextNameIndex가 반환하는 초기 인덱스 값은 0입니다. 다음의 값은 0이 반환되서 루프가 중지되기 전까지 그것이 마지막으로 반환한(그리고 nextName과 nextValue를 위해 주어진) 값입니다. 예를 들어, 한 프록시 인스턴스가 for..in의 루프를 위해 세 개의 "속성들" 을 포함하고 있다고 가정하고, 이것은 nextNameIndex와 nextName이 사용되는 방법입니다:

ActionScript Code:
for (var prop:String in proxy) {
    trace(prop);
}


 

Code:
for (var prop:String in proxy) {
	[ proxy.nextNameIndex(0) -> return 1 ]
	[ proxy.nextName(1) -> return "x" ]
	[ prop = "x" ]
	trace(prop); // x
	(end for block, repeat)
	[ proxy.nextNameIndex(1) -> return 2 ]
	[ proxy.nextName(2) -> return "y" ]
	[ prop = "y" ]
	trace(prop); // y
	(end for block, repeat)
	[ proxy.nextNameIndex(2) -> return 3 ]
	[ proxy.nextName(3) -> return "visible" ]
	[ prop = "visible" ]
	trace(prop); // visible
	[ proxy.nextNameIndex(3) -> return 0 ]
	(0 index, break from for block)
}

for each..in을 사용한다면, nextName 대신 nextValue가 사용되고 prop 변수는 문자열이 아니라 값으로 설정됩니다.

인덱스의 사용이 루프를 돌리기 위한 것이기 때문에, 당신은 보통 배열 안에 열거할 수 있는 속성들 또는 값들을 유지하는 Proxy 인스턴스를 볼 것입니다. 그리고 nextName 또는 nextValue에서는 아마도 배열 안에서 index-1에 있는 요소를 반환할 것입니다 (nextName과 nextValue는 nextNameIndex가 반환한 값으로 인해 루프가 중지되지 않는 한 절대 0을 받지 않는다는 것을 기억하세요.) 여기 nextName과 nextNameIndex를 사용하는 프록시 클래스와 볼 수 있는 출력의 예제가 있습니다. 프록시 메서드는 flash_proxy 네임스페이스에 정의된다는 것을 기억하세요.


Class:

ActionScript Code:
package {
   
    import flash.utils.Proxy;
    import flash.utils.flash_proxy;
   
    public class ProxyEnum extends Proxy {
       
        private var props:Array = ["x", "y", "visible"]; // properties array
       
        // nextNameIndex called when the loop starts
        override flash_proxy function nextNameIndex (index:int):int {
            if (index < props.length) {
                // first call is 0, return 1 + index the index
                // starts with 1, then 2, then 3... etc.
                return index + 1;
            } else {
                // after outside of props bounds,
                // stop the loop returning 0
                return 0;
            }
        }
       
        // nextName called after nextNameIndex returns non-zero
        override flash_proxy function nextName(index:int):String {
            // return the array item in index - 1
            // this relates to a property name in a for..in
            return props[index - 1];
        }
    }
}


Usage:

ActionScript Code:
var proxy:ProxyEnum = new ProxyEnum();
for (var prop in proxy) {
    trace(prop);
}
/* output:
x
y
visible
*/


for..in (또는 for each..in)에서 얻는 값들을 사용자가 사용할 때, 그것이 올바르다는 것을 확실하게 하기 위해 nextValue와 getProperty까지도 정의할 수 있습니다. 수정된 클래스는 같은 속성을 사용하지만 for..in 안에서 보여지는 점들 사이를(?) 연결하기 위해 nextValue와 getProperty 메서드를 추가합니다 (프록시 인스턴스에 넘겨진 표시 객체와 연계되게 만듭니다).


Class:

ActionScript Code:
package {
   
    import flash.display.DisplayObject;
    import flash.utils.Proxy;
    import flash.utils.flash_proxy;
   
    public class ProxyEnum extends Proxy {
       
        private var props:Array = ["x", "y", "visible"]; // properties array
        private var _target:DisplayObject;
       
        function ProxyEnum(target:DisplayObject) {
            _target = target;
        }
       
        // nextNameIndex called when the loop starts
        override flash_proxy function nextNameIndex (index:int):int {
            if (index < props.length) {
                // first call is 0, return 1 + index the index
                // starts with 1, then 2, then 3... etc.
                return index + 1;
            } else {
                // after outside of props bounds,
                // stop the loop returning 0
                return 0;
            }
        }
       
        // nextName called after nextNameIndex returns non-zero
        override flash_proxy function nextName(index:int):String {
            // return the array item in index - 1
            // this relates to a property name in a for..in
            return props[index - 1];
        }
       
        // nextValue called after nextNameIndex returns non-zero
        override flash_proxy function nextValue(index:int):* {
            // return the array item in index - 1
            // this relates to a property value in a for each..in
            var prop:String = props[index - 1];
            return _target[prop];
        }
       
        // gets a property by the name of name
        override flash_proxy function getProperty(name:*):* {
            return _target[name];
        }
    }
}


Usage:

ActionScript Code:
var proxy:ProxyEnum = new ProxyEnum(my_mc);

for (var prop:String in proxy) { // nextName/nextNameIndex
    trace(prop);
    trace(proxy[prop]); // getProperty
}
/* output:
x
34
y
76
visible
true
*/


for each(var value:* in proxy) { // nextValue/nextNameIndex
    trace(value);
}
/* output:
34
76
true
*/

Posted by codeonwort
,