Guest User

Untitled

a guest
Nov 26th, 2013
86
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. package your.package.name
  2. {
  3.     /*************************************************************************
  4.      *
  5.      * http://code.google.com/p/flex-uicomponent-cleaner-and-gc-initiator/
  6.      *
  7.      * UIComponentCleaner class v1.0
  8.      *
  9.      * The UIComponentCleaner class is a static utility class used to break
  10.      * down a display component and its children so they will be prepared for
  11.      * garbage collection eligibility based on the Flash Player's simple
  12.      * reference count technique.  This class has been tested up to version
  13.      * 3.6 of the Adobe Flex SDK.  It has not been tested with versions 4.x
  14.      * of the SDK.
  15.      *
  16.      * Use of this class to remove watchers from the passed
  17.      * UIComponent-derived class instance requires modifying the Flex
  18.      * framework-provided mx.binding::Watcher, mx.binding::PropertyWatcher,
  19.      * mx.binding::FunctionReturnWatcher and
  20.      * mx.binding::RepeaterComponentWatcher classes to allow access to
  21.      * the following private properties declared in those classes:
  22.      *
  23.      * mx.binding::FunctionReturnWatcher - Change the private "document",
  24.      * "parameterFunction", "parentObj" and "functionGetter" properties to
  25.      * properties to public scope.
  26.      *
  27.      * mx.binding::PropertyWatcher - Change the private "parentObj" Object and
  28.      * protected "propertyGetter" Function properties to public scope.
  29.      *
  30.      * mx.binding::RepeaterComponentWatcher - Change the private "clones"
  31.      * Array property to public scope.
  32.      *
  33.      * mx.binding::Watcher - Change the protected "listeners" and "children"
  34.      * Array properties to public scope.
  35.      *
  36.      * If you are statically linking the Flex framework into your application,
  37.      * copy the above listed files from the Flex SDK source directory into
  38.      * your projects main source folder, maintaining the "mx.binding" package
  39.      * composition.  For example, if your main source folder is located in
  40.      * "src/main/flex", you would copy the files to the
  41.      * "src/main/flex/mx/binding" folder before modifying them as instructed
  42.      * above.
  43.      *
  44.      * If you are loading the Flex framework into your application using an
  45.      * RSL, you can follow the directions available at the below link to
  46.      * create your own RSL that can be loaded into your application domain
  47.      * before the Flex framework RSL in order for the modifications to be
  48.      * applied.
  49.      *
  50.      * http://blogs.adobe.com/dloverin/2010/01/how_to_monkey_patch_when_using_flex_rsls.html
  51.      *
  52.      * The UIComponentCleaner class will still function without failing if
  53.      * you choose to not modify the Flex framework classes.  However, its
  54.      * level of success in preparing the passed UIComponent-derived instance
  55.      * for garbage collection will be reduced.
  56.      *
  57.      *************************************************************************
  58.      *
  59.      * Copyright (C) 2011 except where noted by Tommy Baggett
  60.      * (http://www.linkedin.com/in/tommybaggett), Ansuria Solutions LLC
  61.      *
  62.      * Permission is hereby granted, free of charge, to any person obtaining a
  63.      * copy of this software and associated documentation files (the
  64.      * "Software"), to deal in the Software without restriction, including
  65.      * without limitation the rights to use, copy, modify, merge, publish,
  66.      * distribute, sublicense, and/or sell copies of the Software, and to
  67.      * permit persons to whom the Software is furnished to do so, subject to
  68.      * the following conditions:
  69.      *
  70.      * The above copyright notice and this permission notice shall be included
  71.      * in all copies or substantial portions of the Software.
  72.      *
  73.      * The original copyright restrictions, as defined in the license
  74.      * agreement that accompanied it, are respected on Adobe Systems
  75.      * Incorporated code.
  76.      *
  77.      * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  78.      * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  79.      * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  80.      * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  81.      * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  82.      * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  83.      * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  84.      *
  85.      *************************************************************************/
  86.    
  87.     import flash.display.DisplayObject;
  88.     import flash.display.DisplayObjectContainer;
  89.    
  90.     import mx.binding.*;
  91.     import mx.binding.IBindingClient;
  92.     import mx.core.IFlexDisplayObject;
  93.     import mx.core.IUIComponent;
  94.     import mx.core.IVisualElement;
  95.     import mx.core.IVisualElementContainer;
  96.     import mx.core.UIComponent;
  97.     import mx.core.mx_internal;
  98.     import mx.states.State;
  99.    
  100.     use namespace mx_internal;
  101.    
  102.     public class UIComponentCleaner
  103.         {
  104.         /*************************************************************************
  105.          * The primary function of the UIComponentCleaner class is the
  106.          * cleanDisplayComponents() function.  Once a display component is no
  107.          * longer needed and should be released from memory, it should be passed
  108.          * to this function.  Optionally, if you have a Flex mx::Container-derived
  109.          * class instance and you want to only remove its contents, you can use
  110.          * this function and pass a value of true for the cleanChildrenOnly
  111.          * parameter to remove all children and prepare them for the garbage
  112.          * collection process without modifying the passed instance.
  113.          *
  114.          * While the cleanDisplayComponents() function calls the other provided
  115.          * functions to clean bindings, states, watchers, etc., from the passed
  116.          * UIComponent-derived class instance and its children, you may also call
  117.          * them directly if needed.
  118.          *************************************************************************/
  119.         public static function cleanDisplayComponents( mainComponent : IUIComponent, cleanChildrenOnly : Boolean = false, cleanParentReferences : Boolean = true ):void
  120.         {
  121.             // If the main component contains child display components, we should drill down to the
  122.             // bottom-most children by calling ourselves recursively, then work our way back up the display list.
  123.             if ( mainComponent is DisplayObjectContainer )
  124.             {
  125.                 var container : DisplayObjectContainer = mainComponent as DisplayObjectContainer;
  126.                 var index : int = 0;
  127.                 var visualElementContainer:IVisualElementContainer = container as IVisualElementContainer;
  128.                 if (visualElementContainer) {
  129.                     while ( visualElementContainer && visualElementContainer.numElements > index )
  130.                     {
  131.                         // Inspect each child display object.  If it is a UIComponent-derived class,
  132.                         // recursively call ourselves to drill into the originally-passed component's children.
  133.                         var childVisualElement : IVisualElement = visualElementContainer.getElementAt( index );
  134.                         if ( childVisualElement is UIComponent ) {
  135.                             UIComponentCleaner.cleanDisplayComponents( childVisualElement as UIComponent, false, true );
  136.                         }
  137.                        
  138.                         try {
  139.                             // Avoid cleaning classes that won't function correctly afterwards
  140.                             visualElementContainer.removeElementAt( 0 );
  141.                         } catch ( e : Error ) {
  142.                             // TODO:  Add error handling and/or logging as appropriate for your application
  143.                             index++;
  144.                             trace( "Error in cleanDisplayComponents: " + e.message );
  145.                         }
  146.                     }
  147.                 } else {
  148.                     while ( container && container.numChildren > index )
  149.                     {
  150.                         // Inspect each child display object.  If it is a UIComponent-derived class,
  151.                         // recursively call ourselves to drill into the originally-passed component's children.
  152.                         var childComponent : DisplayObject = container.getChildAt( index );
  153.                         if ( childComponent is UIComponent ) {
  154.                             UIComponentCleaner.cleanDisplayComponents( childComponent as UIComponent, false, true );
  155.                         }
  156.                        
  157.                         try {
  158.                             // Avoid cleaning classes that won't function correctly afterwards
  159.                             container.removeChildAt( 0 );
  160.                         }
  161.                         catch ( e : Error )
  162.                         {
  163.                             index++;
  164.                             // TODO:  Add error handling and/or logging as appropriate for your application
  165.                             trace( "Error in cleanDisplayComponents: " + e.message );
  166.                         }
  167.                     }
  168.                 }
  169.             }
  170.            
  171.             if ( !cleanChildrenOnly )
  172.             {
  173.                 try
  174.                 {
  175.                     cleanComponentReferences( mainComponent as UIComponent, cleanParentReferences );
  176.                 }
  177.                 catch ( e : Error )
  178.                 {
  179.                     // TODO:  Add error handling and/or logging as appropriate for your application
  180.                     trace( "Error in cleanDisplayComponents: " + e.message );
  181.                 }
  182.             }
  183.         }
  184.        
  185.         /*************************************************************************
  186.          * The cleanComponentReferences() function calls other UIComponentCleaner
  187.          * static functions to remove the references from the passed
  188.          * UIComponent-derived instance's parent document, bindings, states,
  189.          * watchers, and both the document and owner properties.
  190.          *************************************************************************/
  191.         public static function cleanComponentReferences( component : UIComponent, cleanParentReferences : Boolean ):void
  192.         {
  193.             if ( cleanParentReferences && component.id && component.parentDocument is IFlexDisplayObject && component.parentDocument.hasOwnProperty( component.id ) )
  194.             {
  195.                 try
  196.                 {
  197.                     component.deleteReferenceOnParentDocument( IFlexDisplayObject( component.parentDocument ) );
  198.                 }
  199.                 catch( e : Error )
  200.                 {
  201.                     // TODO:  Add error handling and/or logging as appropriate for your application
  202.                     trace( "Error in cleanComponentReferences, UIComponent::deleteReferenceOnParentDocument() failed: " + e.message );
  203.                 }
  204.             }
  205.            
  206.             cleanBindings( component );
  207.             cleanStates( component );
  208.             cleanWatchers( component );
  209.            
  210.             component.document = null;
  211.             component.owner = null;
  212.         }
  213.        
  214.         /*************************************************************************
  215.          * The cleanBindings() function iterates through the assigned bindings
  216.          * found on the passed component and removes them.  This function is based
  217.          * on the implementation of the Flex framework's
  218.          * BindingManager::executeBindings() function.
  219.          *************************************************************************/
  220.         public static function cleanBindings( component : Object ):void
  221.         {
  222.             if ( component )
  223.             {
  224.                 var binding : Binding;
  225.                 var index : uint;
  226.                 var length : uint;
  227.                
  228.                 // Release all bindings maintained by our component
  229.                 if ( component is IBindingClient || component.hasOwnProperty( "_bindings" ) )
  230.                 {
  231.                     while ( component._bindings.length > 0 )
  232.                     {
  233.                         binding = component._bindings.splice( 0, 1 )[0];
  234.                         cleanBinding( binding );
  235.                     }
  236.                    
  237.                     component._bindingsByDestination = {};
  238.                     component._bindingsBeginWithWord = {};
  239.                 }
  240.                
  241.                 // Release parent document bindings to our component
  242.                 var componentID : String = component.id;
  243.                 if ( componentID != null )
  244.                 {
  245.                     var document : Object = component.descriptor && component.descriptor.document ? component.descriptor.document : component.parentDocument;
  246.                     var componentIDFW : String = getFirstWord( componentID );
  247.                     if ( document && ( document is IBindingClient || document.hasOwnProperty( "_bindingsByDestination" ) ) &&
  248.                         document._bindingsByDestination && document._bindingsBeginWithWord[componentIDFW] )
  249.                     {
  250.                         // Track the number of deletions to know when to stop iterating the bindings array
  251.                         var deletedCount : uint = 0;
  252.                        
  253.                         for ( var bindingID : String in document._bindingsByDestination )
  254.                         {
  255.                             if ( bindingID.charAt(0) == componentID.charAt(0) )
  256.                             {
  257.                                 if ( bindingID.indexOf( componentID + "." ) == 0 ||
  258.                                     bindingID.indexOf( componentID + "[" ) == 0 ||
  259.                                     bindingID == componentID )
  260.                                 {
  261.                                     binding = document._bindingsByDestination[bindingID];
  262.                                     if ( binding != null )
  263.                                     {
  264.                                         cleanBinding( binding );
  265.                                         document._bindingsByDestination[bindingID] = null;
  266.                                         delete document._bindingsByDestination[bindingID];
  267.                                        
  268.                                         deletedCount++;
  269.                                     }
  270.                                 }
  271.                             }
  272.                         }
  273.                        
  274.                         if ( deletedCount > 0 )
  275.                         {
  276.                             for ( index = 0, length = document._bindings.length; index < length && deletedCount > 0; index++ )
  277.                             {
  278.                                 binding = document._bindings[ index ] as Binding;
  279.                                 if ( binding != null && binding.document == null )
  280.                                 {
  281.                                     document._bindings.splice( index--, 1 );
  282.                                     deletedCount--;
  283.                                 }
  284.                             }
  285.                         }
  286.                     }
  287.                 }
  288.             }
  289.         }
  290.        
  291.         /*************************************************************************
  292.          * The cleanStates() function removes any states that are assigned to the
  293.          * passed UIComponent-derived instance and also clears their "target"
  294.          * property values.
  295.          *************************************************************************/
  296.         static public function cleanStates( component : UIComponent ):void
  297.         {
  298.             try
  299.             {
  300.                 // Iterate through the component's states and clean them up
  301.                 // in preparation for garbage collection.
  302.                 while ( component.states && component.states.length > 0 )
  303.                 {
  304.                     var state : State = component.states.pop() as State;
  305.                    
  306.                     while ( state.overrides && state.overrides.length > 0 )
  307.                     {
  308.                         var override : Object = state.overrides.pop();
  309.                        
  310.                         if ( override.hasOwnProperty( "target" ) )
  311.                         {
  312.                             override.target = null;
  313.                         }
  314.                     }
  315.                 }
  316.             }
  317.             catch( e : Error )
  318.             {
  319.                 // TODO:  Add error handling and/or logging as appropriate for your application
  320.                 trace( "Error in cleanStates: " + e.message );
  321.             }
  322.         }
  323.        
  324.         /*************************************************************************
  325.          * The cleanWatchers() function removes any watchers that are assigned to
  326.          * the passed UIComponent-derived instance by the MXML compiler.  Note
  327.          * that it does NOT remove ChangeWatcher instances that were manually
  328.          * added using the BindingUtils class.
  329.          *************************************************************************/
  330.         static public function cleanWatchers( component : Object ):void
  331.         {
  332.             try
  333.             {
  334.                 if ( component._watchers )
  335.                 {
  336.                     // Verify required Flex framework modifications have been made
  337.                     // before attempting to clean up watchers.  Note that this isn't
  338.                     // a thorough check as it only checks one modified property on
  339.                     // the base Watcher class.  Any error resulting from an incomplete
  340.                     // modification of the framework source will be caught by our
  341.                     // try/catch block.
  342.                     var watcher : Watcher = component._watchers[0];
  343.                     if ( !watcher || !watcher.hasOwnProperty( "listeners" ) )
  344.                     {
  345.                         return;
  346.                     }
  347.                    
  348.                     while ( component._watchers && component._watchers.length > 0 )
  349.                     {
  350.                         watcher = component._watchers.splice( 0, 1 )[0];
  351.                         if ( watcher )
  352.                         {
  353.                             cleanWatcher( watcher );
  354.                         }
  355.                     }
  356.                 }
  357.             }
  358.             catch( e : Error )
  359.             {
  360.                 // TODO:  Add error handling and/or logging as appropriate for your application
  361.                 trace( "Error in cleanWatchers: " + e.message );
  362.             }
  363.         }
  364.        
  365.         /*************************************************************************
  366.          * The getFirstWord() function is a private helper for cleanBindings().
  367.          * Its functionality is duplicated from the Flex framework's
  368.          * BindingManager class
  369.          *************************************************************************/
  370.         ////////////////////////////////////////////////////////////////////////////////
  371.         //
  372.         //  ADOBE SYSTEMS INCORPORATED
  373.         //  This function copyright 2003-2007 Adobe Systems Incorporated
  374.         //  All Rights Reserved.
  375.         //
  376.         //  NOTICE: Adobe permits you to use, modify, and distribute this function
  377.         //  in accordance with the terms of the license agreement accompanying it.
  378.         //
  379.         ////////////////////////////////////////////////////////////////////////////////
  380.         static private function getFirstWord( destStr : String ):String
  381.         {
  382.             // indexPeriod and indexBracket will be equal only if they
  383.             // both are -1.
  384.             var indexPeriod : int = destStr.indexOf(".");
  385.             var indexBracket : int = destStr.indexOf("[");
  386.             if ( indexPeriod == indexBracket )
  387.                 return destStr;
  388.            
  389.             // Get the characters leading up to the first period or
  390.             // bracket.
  391.             var minIndex : int = Math.min( indexPeriod, indexBracket );
  392.             if ( minIndex == -1 )
  393.                 minIndex = Math.max( indexPeriod, indexBracket );
  394.            
  395.             return destStr.substr( 0, minIndex );
  396.         }
  397.        
  398.         /*************************************************************************
  399.          * The cleanBinding() function is a private helper for cleanBindings().
  400.          *************************************************************************/
  401.         static private function cleanBinding( binding : Binding ):void
  402.         {
  403.             binding.document = null;
  404.             binding.srcFunc = null;
  405.             binding.destFunc = null;
  406.             binding.destString = null;
  407.             binding.twoWayCounterpart = null;
  408.         }
  409.        
  410.         static private function cleanWatcher( watcher : Watcher ):void
  411.         {
  412.             // The Watcher instance is cast to an Object in this function to avoid any compiler
  413.             // complaints if the needed Flex framework modifications haven't been made.
  414.            
  415.             if ( watcher != null )
  416.             {
  417.                 // Call ourself recursively to eliminate child watchers
  418.                 if ( Object(watcher).children != null )
  419.                 {
  420.                     while ( Object(watcher).children.length > 0 )
  421.                     {
  422.                         var childWatcher : Watcher = Object(watcher).children.splice(0, 1 )[0];
  423.                         if ( childWatcher != null )
  424.                         {
  425.                             cleanWatcher( childWatcher );
  426.                         }
  427.                     }
  428.                 }
  429.                
  430.                 // Clear all associated bindings
  431.                 if ( Object(watcher).listeners != null )
  432.                 {
  433.                     while ( Object(watcher).listeners.length > 0 )
  434.                     {
  435.                         var binding : Binding = Object(watcher).listeners.splice(0, 1 )[0];
  436.                         if ( binding != null )
  437.                         {
  438.                             cleanBinding( binding );
  439.                         }
  440.                     }
  441.                 }
  442.                
  443.                 watcher.value = null;
  444.                
  445.                 if ( watcher is PropertyWatcher )
  446.                 {
  447.                     Object( watcher ).parentObj = null;
  448.                     Object( watcher ).propertyGetter = null;
  449.                 }
  450.                
  451.                 if ( watcher is FunctionReturnWatcher )
  452.                 {
  453.                     Object( watcher ).parentObj = null;
  454.                     Object( watcher ).functionGetter = null;
  455.                     Object( watcher ).document = null;
  456.                     Object( watcher ).parameterFunction = null;
  457.                 }
  458.                
  459.                 if ( watcher is RepeaterComponentWatcher && Object( watcher ).clones.length > 0 )
  460.                 {
  461.                     while ( Object(watcher).clones.length > 0 )
  462.                     {
  463.                         var childRepeaterWatcher : RepeaterComponentWatcher = Object(watcher).clones.splice( 0, 1 )[0];
  464.                         if ( childRepeaterWatcher != null )
  465.                         {
  466.                             cleanWatcher( childRepeaterWatcher );
  467.                         }
  468.                     }
  469.                 }
  470.             }
  471.         }
  472.     }
  473. }
Advertisement
Add Comment
Please, Sign In to add comment