Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package your.package.name
- {
- /*************************************************************************
- *
- * http://code.google.com/p/flex-uicomponent-cleaner-and-gc-initiator/
- *
- * UIComponentCleaner class v1.0
- *
- * The UIComponentCleaner class is a static utility class used to break
- * down a display component and its children so they will be prepared for
- * garbage collection eligibility based on the Flash Player's simple
- * reference count technique. This class has been tested up to version
- * 3.6 of the Adobe Flex SDK. It has not been tested with versions 4.x
- * of the SDK.
- *
- * Use of this class to remove watchers from the passed
- * UIComponent-derived class instance requires modifying the Flex
- * framework-provided mx.binding::Watcher, mx.binding::PropertyWatcher,
- * mx.binding::FunctionReturnWatcher and
- * mx.binding::RepeaterComponentWatcher classes to allow access to
- * the following private properties declared in those classes:
- *
- * mx.binding::FunctionReturnWatcher - Change the private "document",
- * "parameterFunction", "parentObj" and "functionGetter" properties to
- * properties to public scope.
- *
- * mx.binding::PropertyWatcher - Change the private "parentObj" Object and
- * protected "propertyGetter" Function properties to public scope.
- *
- * mx.binding::RepeaterComponentWatcher - Change the private "clones"
- * Array property to public scope.
- *
- * mx.binding::Watcher - Change the protected "listeners" and "children"
- * Array properties to public scope.
- *
- * If you are statically linking the Flex framework into your application,
- * copy the above listed files from the Flex SDK source directory into
- * your projects main source folder, maintaining the "mx.binding" package
- * composition. For example, if your main source folder is located in
- * "src/main/flex", you would copy the files to the
- * "src/main/flex/mx/binding" folder before modifying them as instructed
- * above.
- *
- * If you are loading the Flex framework into your application using an
- * RSL, you can follow the directions available at the below link to
- * create your own RSL that can be loaded into your application domain
- * before the Flex framework RSL in order for the modifications to be
- * applied.
- *
- * http://blogs.adobe.com/dloverin/2010/01/how_to_monkey_patch_when_using_flex_rsls.html
- *
- * The UIComponentCleaner class will still function without failing if
- * you choose to not modify the Flex framework classes. However, its
- * level of success in preparing the passed UIComponent-derived instance
- * for garbage collection will be reduced.
- *
- *************************************************************************
- *
- * Copyright (C) 2011 except where noted by Tommy Baggett
- * (http://www.linkedin.com/in/tommybaggett), Ansuria Solutions LLC
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * The original copyright restrictions, as defined in the license
- * agreement that accompanied it, are respected on Adobe Systems
- * Incorporated code.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- *************************************************************************/
- import flash.display.DisplayObject;
- import flash.display.DisplayObjectContainer;
- import mx.binding.*;
- import mx.binding.IBindingClient;
- import mx.core.IFlexDisplayObject;
- import mx.core.IUIComponent;
- import mx.core.IVisualElement;
- import mx.core.IVisualElementContainer;
- import mx.core.UIComponent;
- import mx.core.mx_internal;
- import mx.states.State;
- use namespace mx_internal;
- public class UIComponentCleaner
- {
- /*************************************************************************
- * The primary function of the UIComponentCleaner class is the
- * cleanDisplayComponents() function. Once a display component is no
- * longer needed and should be released from memory, it should be passed
- * to this function. Optionally, if you have a Flex mx::Container-derived
- * class instance and you want to only remove its contents, you can use
- * this function and pass a value of true for the cleanChildrenOnly
- * parameter to remove all children and prepare them for the garbage
- * collection process without modifying the passed instance.
- *
- * While the cleanDisplayComponents() function calls the other provided
- * functions to clean bindings, states, watchers, etc., from the passed
- * UIComponent-derived class instance and its children, you may also call
- * them directly if needed.
- *************************************************************************/
- public static function cleanDisplayComponents( mainComponent : IUIComponent, cleanChildrenOnly : Boolean = false, cleanParentReferences : Boolean = true ):void
- {
- // If the main component contains child display components, we should drill down to the
- // bottom-most children by calling ourselves recursively, then work our way back up the display list.
- if ( mainComponent is DisplayObjectContainer )
- {
- var container : DisplayObjectContainer = mainComponent as DisplayObjectContainer;
- var index : int = 0;
- var visualElementContainer:IVisualElementContainer = container as IVisualElementContainer;
- if (visualElementContainer) {
- while ( visualElementContainer && visualElementContainer.numElements > index )
- {
- // Inspect each child display object. If it is a UIComponent-derived class,
- // recursively call ourselves to drill into the originally-passed component's children.
- var childVisualElement : IVisualElement = visualElementContainer.getElementAt( index );
- if ( childVisualElement is UIComponent ) {
- UIComponentCleaner.cleanDisplayComponents( childVisualElement as UIComponent, false, true );
- }
- try {
- // Avoid cleaning classes that won't function correctly afterwards
- visualElementContainer.removeElementAt( 0 );
- } catch ( e : Error ) {
- // TODO: Add error handling and/or logging as appropriate for your application
- index++;
- trace( "Error in cleanDisplayComponents: " + e.message );
- }
- }
- } else {
- while ( container && container.numChildren > index )
- {
- // Inspect each child display object. If it is a UIComponent-derived class,
- // recursively call ourselves to drill into the originally-passed component's children.
- var childComponent : DisplayObject = container.getChildAt( index );
- if ( childComponent is UIComponent ) {
- UIComponentCleaner.cleanDisplayComponents( childComponent as UIComponent, false, true );
- }
- try {
- // Avoid cleaning classes that won't function correctly afterwards
- container.removeChildAt( 0 );
- }
- catch ( e : Error )
- {
- index++;
- // TODO: Add error handling and/or logging as appropriate for your application
- trace( "Error in cleanDisplayComponents: " + e.message );
- }
- }
- }
- }
- if ( !cleanChildrenOnly )
- {
- try
- {
- cleanComponentReferences( mainComponent as UIComponent, cleanParentReferences );
- }
- catch ( e : Error )
- {
- // TODO: Add error handling and/or logging as appropriate for your application
- trace( "Error in cleanDisplayComponents: " + e.message );
- }
- }
- }
- /*************************************************************************
- * The cleanComponentReferences() function calls other UIComponentCleaner
- * static functions to remove the references from the passed
- * UIComponent-derived instance's parent document, bindings, states,
- * watchers, and both the document and owner properties.
- *************************************************************************/
- public static function cleanComponentReferences( component : UIComponent, cleanParentReferences : Boolean ):void
- {
- if ( cleanParentReferences && component.id && component.parentDocument is IFlexDisplayObject && component.parentDocument.hasOwnProperty( component.id ) )
- {
- try
- {
- component.deleteReferenceOnParentDocument( IFlexDisplayObject( component.parentDocument ) );
- }
- catch( e : Error )
- {
- // TODO: Add error handling and/or logging as appropriate for your application
- trace( "Error in cleanComponentReferences, UIComponent::deleteReferenceOnParentDocument() failed: " + e.message );
- }
- }
- cleanBindings( component );
- cleanStates( component );
- cleanWatchers( component );
- component.document = null;
- component.owner = null;
- }
- /*************************************************************************
- * The cleanBindings() function iterates through the assigned bindings
- * found on the passed component and removes them. This function is based
- * on the implementation of the Flex framework's
- * BindingManager::executeBindings() function.
- *************************************************************************/
- public static function cleanBindings( component : Object ):void
- {
- if ( component )
- {
- var binding : Binding;
- var index : uint;
- var length : uint;
- // Release all bindings maintained by our component
- if ( component is IBindingClient || component.hasOwnProperty( "_bindings" ) )
- {
- while ( component._bindings.length > 0 )
- {
- binding = component._bindings.splice( 0, 1 )[0];
- cleanBinding( binding );
- }
- component._bindingsByDestination = {};
- component._bindingsBeginWithWord = {};
- }
- // Release parent document bindings to our component
- var componentID : String = component.id;
- if ( componentID != null )
- {
- var document : Object = component.descriptor && component.descriptor.document ? component.descriptor.document : component.parentDocument;
- var componentIDFW : String = getFirstWord( componentID );
- if ( document && ( document is IBindingClient || document.hasOwnProperty( "_bindingsByDestination" ) ) &&
- document._bindingsByDestination && document._bindingsBeginWithWord[componentIDFW] )
- {
- // Track the number of deletions to know when to stop iterating the bindings array
- var deletedCount : uint = 0;
- for ( var bindingID : String in document._bindingsByDestination )
- {
- if ( bindingID.charAt(0) == componentID.charAt(0) )
- {
- if ( bindingID.indexOf( componentID + "." ) == 0 ||
- bindingID.indexOf( componentID + "[" ) == 0 ||
- bindingID == componentID )
- {
- binding = document._bindingsByDestination[bindingID];
- if ( binding != null )
- {
- cleanBinding( binding );
- document._bindingsByDestination[bindingID] = null;
- delete document._bindingsByDestination[bindingID];
- deletedCount++;
- }
- }
- }
- }
- if ( deletedCount > 0 )
- {
- for ( index = 0, length = document._bindings.length; index < length && deletedCount > 0; index++ )
- {
- binding = document._bindings[ index ] as Binding;
- if ( binding != null && binding.document == null )
- {
- document._bindings.splice( index--, 1 );
- deletedCount--;
- }
- }
- }
- }
- }
- }
- }
- /*************************************************************************
- * The cleanStates() function removes any states that are assigned to the
- * passed UIComponent-derived instance and also clears their "target"
- * property values.
- *************************************************************************/
- static public function cleanStates( component : UIComponent ):void
- {
- try
- {
- // Iterate through the component's states and clean them up
- // in preparation for garbage collection.
- while ( component.states && component.states.length > 0 )
- {
- var state : State = component.states.pop() as State;
- while ( state.overrides && state.overrides.length > 0 )
- {
- var override : Object = state.overrides.pop();
- if ( override.hasOwnProperty( "target" ) )
- {
- override.target = null;
- }
- }
- }
- }
- catch( e : Error )
- {
- // TODO: Add error handling and/or logging as appropriate for your application
- trace( "Error in cleanStates: " + e.message );
- }
- }
- /*************************************************************************
- * The cleanWatchers() function removes any watchers that are assigned to
- * the passed UIComponent-derived instance by the MXML compiler. Note
- * that it does NOT remove ChangeWatcher instances that were manually
- * added using the BindingUtils class.
- *************************************************************************/
- static public function cleanWatchers( component : Object ):void
- {
- try
- {
- if ( component._watchers )
- {
- // Verify required Flex framework modifications have been made
- // before attempting to clean up watchers. Note that this isn't
- // a thorough check as it only checks one modified property on
- // the base Watcher class. Any error resulting from an incomplete
- // modification of the framework source will be caught by our
- // try/catch block.
- var watcher : Watcher = component._watchers[0];
- if ( !watcher || !watcher.hasOwnProperty( "listeners" ) )
- {
- return;
- }
- while ( component._watchers && component._watchers.length > 0 )
- {
- watcher = component._watchers.splice( 0, 1 )[0];
- if ( watcher )
- {
- cleanWatcher( watcher );
- }
- }
- }
- }
- catch( e : Error )
- {
- // TODO: Add error handling and/or logging as appropriate for your application
- trace( "Error in cleanWatchers: " + e.message );
- }
- }
- /*************************************************************************
- * The getFirstWord() function is a private helper for cleanBindings().
- * Its functionality is duplicated from the Flex framework's
- * BindingManager class
- *************************************************************************/
- ////////////////////////////////////////////////////////////////////////////////
- //
- // ADOBE SYSTEMS INCORPORATED
- // This function copyright 2003-2007 Adobe Systems Incorporated
- // All Rights Reserved.
- //
- // NOTICE: Adobe permits you to use, modify, and distribute this function
- // in accordance with the terms of the license agreement accompanying it.
- //
- ////////////////////////////////////////////////////////////////////////////////
- static private function getFirstWord( destStr : String ):String
- {
- // indexPeriod and indexBracket will be equal only if they
- // both are -1.
- var indexPeriod : int = destStr.indexOf(".");
- var indexBracket : int = destStr.indexOf("[");
- if ( indexPeriod == indexBracket )
- return destStr;
- // Get the characters leading up to the first period or
- // bracket.
- var minIndex : int = Math.min( indexPeriod, indexBracket );
- if ( minIndex == -1 )
- minIndex = Math.max( indexPeriod, indexBracket );
- return destStr.substr( 0, minIndex );
- }
- /*************************************************************************
- * The cleanBinding() function is a private helper for cleanBindings().
- *************************************************************************/
- static private function cleanBinding( binding : Binding ):void
- {
- binding.document = null;
- binding.srcFunc = null;
- binding.destFunc = null;
- binding.destString = null;
- binding.twoWayCounterpart = null;
- }
- static private function cleanWatcher( watcher : Watcher ):void
- {
- // The Watcher instance is cast to an Object in this function to avoid any compiler
- // complaints if the needed Flex framework modifications haven't been made.
- if ( watcher != null )
- {
- // Call ourself recursively to eliminate child watchers
- if ( Object(watcher).children != null )
- {
- while ( Object(watcher).children.length > 0 )
- {
- var childWatcher : Watcher = Object(watcher).children.splice(0, 1 )[0];
- if ( childWatcher != null )
- {
- cleanWatcher( childWatcher );
- }
- }
- }
- // Clear all associated bindings
- if ( Object(watcher).listeners != null )
- {
- while ( Object(watcher).listeners.length > 0 )
- {
- var binding : Binding = Object(watcher).listeners.splice(0, 1 )[0];
- if ( binding != null )
- {
- cleanBinding( binding );
- }
- }
- }
- watcher.value = null;
- if ( watcher is PropertyWatcher )
- {
- Object( watcher ).parentObj = null;
- Object( watcher ).propertyGetter = null;
- }
- if ( watcher is FunctionReturnWatcher )
- {
- Object( watcher ).parentObj = null;
- Object( watcher ).functionGetter = null;
- Object( watcher ).document = null;
- Object( watcher ).parameterFunction = null;
- }
- if ( watcher is RepeaterComponentWatcher && Object( watcher ).clones.length > 0 )
- {
- while ( Object(watcher).clones.length > 0 )
- {
- var childRepeaterWatcher : RepeaterComponentWatcher = Object(watcher).clones.splice( 0, 1 )[0];
- if ( childRepeaterWatcher != null )
- {
- cleanWatcher( childRepeaterWatcher );
- }
- }
- }
- }
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment