PureMVC Architects Lounge

PureMVC Manifold => MultiCore Version => Topic started by: denne on June 06, 2009, 05:24:20



Title: Changes to observerlist when notifying observers not used.
Post by: denne on June 06, 2009, 05:24:20
Hello PureMVC users!
Im a new user to puremvc and have been playing with PureMVC the last week to find out how its working. I ported the puremvc4gwt loginsample to this puremvc multicore version and saw a small difference in how the code notifies observers.


From the loginsample from puremvc4gwt I found out that the StartupCommand adds two subcommands (PrepView and PrepModel) which when executed with the Startup event registers the proxy and mediators.

In the official multicore version in method notifyObservers in the View class I found that (marked in bold in the code below) the code creates a private copy of the observer list and uses this to iterate.

The issue I saw when running the loginsample with the official puremvc multicore version was that any new or changes to observersMap registered during the notification of the STARTUP was ignored.

As you see in the code below, the private copy doesnt see any new observers, but actually there has been one registered by the StartupCommand that also listens to the same Startup notification (SplashScreenMediator also listens to STARTUP command). It is present in the observermap and observers_ref but not in the array copy observers.

I did a quick change to the code, to work on the "live" list of observers_ref instead of a private copy, and this worked. Any changes to the list of observers are added to the end of the list so if any new observers are registered they are executed in the end of the iteration. This is also how puremvc4gwt does it in its code.

What is the reason behind isolation the observerlist in a private copy? Is it the loginsample that is not following best practice?
 
   public void notifyObservers( INotification note )
   {
      List<IObserver> observers_ref = (List<IObserver>) this.observerMap.get(note.getName());
      if (observers_ref != null) {
           
      // Copy observers from reference array to working array,
                // since the reference array may change during the
                // notification loop

         Object[] observers = (Object[])observers_ref.toArray();
         
         // Notify Observers from the working array
         for (int i = 0; i < observers.length; i++) {
            IObserver observer = (IObserver)observers;
            observer.notifyObserver(note);
         }
      }
   }


Title: Re: Changes to observerlist when notifying observers not used.
Post by: fede on June 08, 2009, 09:22:28
in my opinion it is far more safe ti itrate on the local copy and not on the original list.
This is because in a multithreaded environment if the list is modified while you are iterating it you can have strange behavior. that said, in gwt  port wer are in a javascript environment and this is monothreaded so it is not an issue but anyway it is more clean because if you notify STARTUP your notification go to the listeners of STARTUP in tha t moment. if soomeone attach new listeners to STARTUP during the STARTUP you will see them only on the next notification of STARTUP.

More on this... it is not very clean add STARTUP listeners during STARTUP. you shuld add all yopur STARPUP listeners statically during the application setup and then invoke once the STARTUP notification.


Title: Re: Changes to observerlist when notifying observers not used.
Post by: aquinault on June 10, 2009, 05:04:40
It's more safe to iterate on a local copy.
There is a copy because if a mediator is removed during the following code :

for (int i = 0; i < observers.length; i++)

then observers.length become wrong and we could have a null pointer exception during the cast :
IObserver observer = (IObserver)observers;

Anthony.