Futurescale, Inc. PureMVC Home

The PureMVC Framework Code at the Speed of Thought


Over 10 years of community discussion and knowledge are maintained here as a read-only archive.

New discussions should be taken up in issues on the appropriate projects at https://github.com/PureMVC

Pages: [1] 2
Print
Author Topic: RetrieveProxy Returning NULL  (Read 29657 times)
Cerin
Newbie
*
Posts: 5


View Profile Email
« on: April 19, 2008, 11:09:10 »

Hi,

I'm trying to get started on a simple PureMVC app with version 2.0.3. I have a startup command that registers a proxy and mediator via:

facade.registerProxy( new WorldProxy() );
facade.registerMediator( new ApplicationMediator( main ) );

The ApplicationMediator further registers a MenuMediator:

facade.registerMediator( new MenuMediator(menuSprite) );

The problem is that in the MenuMediator, I'm unable to retrieve my WorldProxy, like:

proxy = facade.retrieveProxy( WorldProxy.NAME ) as WorldProxy;
trace('proxy:'+proxy)

The trace shows that proxy is NULL. How can this be if I've registered the proxy?

Logged
Cerin
Newbie
*
Posts: 5


View Profile Email
« Reply #1 on: April 19, 2008, 11:40:35 »

I tried moving around the call to retrieveProxy, and it returns NULL regardless of what class, constructor, or function it's called from.
Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #2 on: April 19, 2008, 01:47:41 »

Are you certain you're using the Standard Version? If you are using the MultiCore Version you would see this behavior in constructors of Mediators and Proxies because they haven't yet had initializeNotifier called, and so the facade property is not yet set.

This is not an issue in the Standard Version, however and indicates perhaps WorldProxy.NAME isn't defined, or for some reason, failed construction.

Are you using Flex Builder? If so, you could save yourself some time by using the debugger. Just set a breakpoint on the line where you create and register WorldProxy, run in debug mode, and step into the code.

-=Cliff>
Logged
Cerin
Newbie
*
Posts: 5


View Profile Email
« Reply #3 on: April 19, 2008, 02:01:12 »

Yes, I'm definitely using the Standard version. I'm also sure WorldProxy.NAME is defined in my WorldProxy.as like:

      public static const NAME:String = "WorldProxy"

Unfortunately, I'm using Flex Builder Alpha on Linux, and I think the debugger is one of many features that don't work yet.

Just to get a feel for how the proxy is registered, I replaced registerProxy in the standard Model.as with:

      public function registerProxy( proxy:IProxy ) : void
      {
         trace('model.registerProxy:'+proxy)
         trace('model.registerProxy.proxyMap.length.before:'+proxyMap.length)
         trace('model.registerProxy.proxyName():'+proxy.getProxyName())
         proxyMap[ proxy.getProxyName() ] = proxy;
         trace('model.registerProxy.proxyMap.length.after:'+proxyMap.length)
         proxy.onRegister();
      }

And this is the output I get:

model.registerProxy:[object WorldProxy]
model.registerProxy.proxyMap.length.before:0
model.registerProxy.proxyName():Proxy
model.registerProxy.proxyMap.length.after:0

I can't begin to explain my surprise at how proxyMap has the same length, even though a value was added, or how the proxy name is incorrect. Could this be a bug in mxmlc?
Logged
Rhysyngsun
Courseware Beta
Sr. Member
***
Posts: 51

Nathan Levesque

 - rhysyngsun@gmail.com  - rhysyngsun
View Profile WWW Email
« Reply #4 on: April 19, 2008, 03:04:46 »

Cerin, are you passing NAME as the first parameter to the super constructor? That was the first thing that came to mind for me, your constructor for WorldProxy should look like:

:
public function WorldProxy()
{
    super( NAME, null );
}

Name is the important part, null would be whatever you're initializing data to.
Logged

puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #5 on: April 19, 2008, 03:34:02 »

Cerin,

When an array in ActionScript is used as an associative array, the length property does not show the number of alphanumeric keys stored in the array at all. Length only works if you're using numeric (strict) indices.

I'm going to move this thread back to the AS3 Standard version discussion group, as the unit tests are all passing for the current version, and so I'm pretty sure it's not a framework bug.

-=Cliff>
Logged
Cerin
Newbie
*
Posts: 5


View Profile Email
« Reply #6 on: April 19, 2008, 05:04:26 »

Rhysyngsun, Thanks, that's exactly what I was missing! Now it's working perfectly.

puremvc, Thanks for the pointer. Glad to know I'm not going insane ;)
Logged
jeremyspouken
Newbie
*
Posts: 2


View Profile Email
« Reply #7 on: September 12, 2008, 01:12:41 »

Hi,

I'm having the exact same problem. But haven't managed to sort it out and fix it.

I have two proxies and both of them return NULL using the standard version AS3.

TypeError: Error #1009: Cannot access a property or method of a null object reference.

Don't know what I'm missing :(
Registered from the StartupCommand
:
    facade.registerProxy( new QuestionsProxy() );

From the QuestionsMediator I call it
:
public function QuestionMediator(viewComponent:Object) {
// pass the viewComponent to the superclass where
// it will be stored in the inherited viewComponent property
super(NAME, viewComponent);

// Proxy
_questionProxy = facade.retrieveProxy( QuestionsProxy.NAME ) as QuestionsProxy;
_questionProxy.getQuestions( null ); // CANT access getQuestions object reference is null why>?????

trace(_questionProxy); // Returns NULL
}
:
/*
Proxy - PureMVC
*/
package com.jer.voting.model
{
import org.puremvc.as3.interfaces.IProxy;
import org.puremvc.as3.patterns.proxy.Proxy;

import lib.jer.as3.net.RemoteObject;
import lib.jer.as3.events.RemoteObjectEvent;
import com.jer.voting.ApplicationFacade;

/**
* A proxy
*/
public class QuestionsProxy extends Proxy implements IProxy {

public static const NAME:String = "QuestionsProxy";
private var connection:RemoteObject;
private var gateway:String = ApplicationFacade.GATEWAY;

public function QuestionsProxy(data:Object = null) {
super(NAME, data);
init();
}

private function init():void {
connection = new RemoteObject(gateway);
connection.addEventListener(RemoteObjectEvent.RESULT, onRemoteResult);
connection.addEventListener(RemoteObjectEvent.FAULT, onRemoteFault);
}

private function onRemoteResult(event:RemoteObjectEvent):void {
sendNotification(ApplicationFacade.REMOTE_RESULT, event.data);
}

private function onRemoteFault(event:RemoteObjectEvent):void {
trace("FAULT : " + event);
}

public function getQuestions(s:Object):void {
trace( "Question" );
if (connection) {
trace("SENDING : " + s);
connection.method = "getPoll";
connection.send();
}
}

}
}
« Last Edit: September 12, 2008, 01:20:34 by jeremyspouken » Logged
jeremyspouken
Newbie
*
Posts: 2


View Profile Email
« Reply #8 on: September 12, 2008, 01:26:03 »

Forget about it I was Registering the Mediators First!!!!!!!!!!!!!!! Dumb :( ... well it happens.
Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #9 on: September 13, 2008, 05:09:15 »

Also, array length dosent increase when it is used as an associative array / map. That's just ActionScript.

Wow, I'm amazed the debugger doesn't work on Linux. They aren't actually asking money for it are they? Without the debugger you might as well be using notpad and ant.

-=Cliff>
Logged
tomaugerdotcom
Newbie
*
Posts: 8


View Profile Email
« Reply #10 on: July 17, 2009, 10:37:12 »

Arrrrg. Well, I've held off long enough posting a question here I suppose, but now I'm snookered. Same issue; I'll post some code that I believe is relevant:

:
// ApplicationStartup command (partial)

public class ApplicationStartup extends SimpleCommand implements ICommand {

// inherit constructor from SimpleCommand

override public function execute (note:INotification):void {
// get a reference to the main application object through the notification body
var application:Object = note.getBody();

// set up the main mediator that will handle all our sub views
// we have to do this before we initialize the model because the mediator listens to model notifications
facade.registerMediator (new ApplicationMediator (application.stage));

// set up all the different data sources that we'll be using
facade.sendNotification (ApplicationFacade.INIT_MODEL);
}

}

:
// Application Mediator (partial code)
private var pConfigData:PConfigData;

public function ApplicationMediator(viewComponent:DisplayObject) {
super (NAME, viewComponent);
}

override public function listNotificationInterests():Array {
return [
ApplicationFacade.CONFIG_DATA_LOADED
];
}

override public function handleNotification (note:INotification):void {
switch (note.getName()) {
case ApplicationFacade.CONFIG_DATA_LOADED:
pConfigData = facade.retrieveProxy(PConfigData.NAME) as PConfigData;
trace(pConfigData);
break;

}
}

:
// PConfigData proxy (partial code)
public class PConfigData extends Proxy implements IProxy {

public static const NAME:String = 'PConfigData';

private var initData:Object = {
language: 'en'
}

public function PConfigData() {
super(NAME, initData);

sendNotification(ApplicationFacade.CONFIG_DATA_LOADED);
}


// getters and setters to access the data
public function get language():String {
return data.language;
}
public function set language(lang:String):void {
// read-only, but data-bindable
}

}


I'm initializing the mediator before the proxy, but I'm not touching the proxy until that notification that is initiated by the proxy on data load  is received by the Mediator, so I'm really not sure why it's still returning null.

Any help from Cliff or you other genii would be greatly appreciated - though I'm not sure whether this post is too buried to get noticed.

Thanks in advance!

Tom
Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #11 on: July 19, 2009, 08:15:38 »

I don't see where you're registering the Proxy at all here.

Also, you're registering things in the wrong order:
we have to do this before we initialize the model because the mediator listens to model notifications

The startup process should be:

 * Initial application view is built using MXML or whatever.

 * Get the concrete Facade instance. (This causes the commands to be mapped in initializeController)

 * Invoke the concrete Facade's startup method, passing a reference to the view hierarchy just built.

 * Startup sends notification handled by a StartupCommand.
 
 * In StartupCommand:
   
    * Prepare the Model by registering all the initially needed Proxies. DON'T have these Proxies immediately go off talking to services or sending notifications, JUST REGISTER them to make them available.

 * Register the initial Mediator(s) with the components of the view hierarchy.

 * In the onRegister methods of the Mediators, retrieve local references to the frequently used Proxies so that you're not retrieving them multiple times at runtime.

 * Once the startup preparation of Model and View are complete, THEN trigger the calls that would cause the Proxies to sendNotifications the View is interested in.

-=Cliff>
Logged
tomaugerdotcom
Newbie
*
Posts: 8


View Profile Email
« Reply #12 on: July 20, 2009, 04:56:25 »

Thanks Cliff. That makes sense. I'll try it that way and report back on how it went. Thanks for being so active on the boards!

Tom
Logged
tomaugerdotcom
Newbie
*
Posts: 8


View Profile Email
« Reply #13 on: July 20, 2009, 11:09:29 »

Yes. That worked! Thanks. Here's what I've done:

So, in the StartupCommand I initialize the data model (which basically just registers the Proxy), then I initialize the main Mediator and pass it the stage:

:
override public function execute (note:INotification):void {
// get a reference to the main application object through the notification body
var application:Object = note.getBody();

// set up all the different data sources that we'll be using
facade.sendNotification (ApplicationFacade.INIT_MODEL);

// set up the main mediator that will handle all our sub views
facade.registerMediator (new ApplicationMediator (application.stage));
}

As before, all the InitModel command does is register the Proxy:
:
override public function execute (note:INotification):void {
facade.registerProxy(new PConfigData()); // configuration data (language etc)
}

In my Proxy, I've removed the "load complete" notification from the constructor method. Instead, I've created a new method called "populate()" which is invoked by the main view Mediator. The populate() method then grabs the data from wherever it has to, and eventually, when that data is loaded (synchronously or asynchronously) will send the CONFIG_DATA_LOADED notification:

:
facade.sendNotification(ApplicationFacade.CONFIG_DATA_LOADED);
Finally, the Mediator gets a reference to the config data Proxy in its onRegister() method (thanks - I didn't know that was there). Immediately thereafter it calls the populate() method on it, thus starting the data load process.

And then we register this Mediator to listen for the CONFIG_DATA_LOADED notification which tells it that the data is populated and ready to use.

:
override public function onRegister():void {
pConfigData = facade.retrieveProxy(PConfigData.NAME) as PConfigData;
pConfigData.populate();
}

override public function listNotificationInterests():Array {
return [
ApplicationFacade.CONFIG_DATA_LOADED
];
}

override public function handleNotification (note:INotification):void {
switch (note.getName()) {
case ApplicationFacade.CONFIG_DATA_LOADED:
trace("Config language: " + pConfigData.language);
break;

}
}

I guess I'm a little concerned because the Mediator is calling a method directly on the Proxy. Is this allowed / correct? Or does that still mean they are too tightly coupled? It almost feels like this "populate()" type method should be something required in the Interface, much like the execute() method on a command, no?

Thanks again for your advice,

Tom
Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #14 on: July 21, 2009, 07:48:47 »

I guess I'm a little concerned because the Mediator is calling a method directly on the Proxy. Is this allowed / correct? Or does that still mean they are too tightly coupled?
There is no problem with the Mediator calling a method on a Proxy.

In the classic MVC pattern, the Model notifies the View which in turn may update the Model.

Sometimes with all the implementation patterns used to carry out MVC in the real world, it's easy to lose sight of the original, simple relationships. Here's a link to a back-to-basics description in the Standard Version Overview presentation:

http://puremvc.tv/#P100/T110

The only variance from the original MVC pattern is that the Model may also notify the Controller (i.e. trigger Commands).

-=Cliff>
« Last Edit: July 21, 2009, 12:29:05 by puremvc » Logged
Pages: [1] 2
Print