16.3 Memory Management Issues with Observer

 <  Day Day Up  >  

In Chapter 5, we learned that event-listener objects registered with an event source must always unregister from that source before being deleted. The same holds true in the Observer pattern ”observers must unregister with their subject before being deleted. For example, suppose we create an OutputPanelView object and register it to observe a Logger instance (as shown in the previous section):

 var outputLog:OutputPanelView = new OutputPanelView(log); log.addObserver(outputLog); 

Later in the program, we decide we no longer want to print log messages to the Output panel, so we delete the variable outputLog . But even with outputLog deleted, messages continue to appear in the Output panel! Why? Because the Logger class stores a reference to OutputPanelView instance, and deleting the variable outputLog does not remove that reference. We must unregister the reference with Logger before deleting outputLog , as follows :

 log.removeObserver(outputLog); delete outputLog; 

To formalize the process of unregistering an observer from its subject, we implement a destroy( ) method on the observer class. For example, the following code shows how we implement destroy( ) for OutputPanelView :

 public function destroy ( ):Void {   log.removeObserver(this); } 

The destroy( ) method's main responsibility is to unregister the observer from its subject; however, destroy( ) can also be used to generally clean up assets used by the observer class. For example, the following code shows the implementation of destroy( ) we use for the TextFieldView class. Here, the destroy( ) method performs unregistration and also removes the log text field from the screen:

 public function destroy ( ):Void {   log.removeObserver(this);   out.removeTextField( ); } 

A similar warning applies to the subject class in the Observer pattern. A subject must be deleted only after ensuring that its observers no longer refer to it. As we've seen in this chapter, each observer class stores a reference to its subject. For example, both the OutputPanelView and the TextFieldView classes store a reference to the Logger class in the property log . If we want to delete a Logger instance, we first have to remove the reference to it in both OutputPanelView and TextFieldView ( assuming instances of those classes are observing the Logger instance). This requires OutputPanelView and TextFieldView to implement a new method, releaseSubject( ) , which sets the property log to null :

 public function releaseSubject( ):Void {   log = null; } 

The Observable class then implements a corresponding method, destroy( ) , which calls releaseSubject( ) on its observers prior to deletion:

 public function destroy ( ):Void {   var observersSnapshot:Array = observers.slice(0);   // Invoke   releaseSubject( )   on all observers.   for (var i:Number = observersSnapshot.length-1; i >= 0; i--) {     observersSnapshot[i].releaseSubject( );   } } 

We can then safely delete a subject by first invoking destroy( ) on it:

 theLog.destroy( ); delete theLog; 

Note that we don't have to manually remove the subject's list of observers; deleting the subject also deletes its observers array automatically.

In situations in which the observers do not need arbitrary access to the subject they are observing, the observers need not store a reference to the subject at all. Instead, a reference to the subject can be passed to the observers via the update( ) method (either as a separate argument or as a property of the info object). The observers can then access the subject at update time via the parameters passed to the update( ) method and then immediately discard the reference to the subject. This prevents dangling references to deleted subjects in observers.

 <  Day Day Up  >  


Essential ActionScript 2.0
Essential ActionScript 2.0
ISBN: 0596006527
EAN: 2147483647
Year: 2004
Pages: 177
Authors: Colin Moock

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net