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]
Print
Author Topic: Facade.removeCore() throws error using FB 4.x framework  (Read 11329 times)
gohloum
Jr. Member
**
Posts: 16


View Profile Email
« on: August 14, 2010, 03:21:43 »

Hey guys,

I have been working with this issue for several hours and I have found that calling the static removeCore() causes an error on line 10632 of UIComponent.

To catch you up with what I have done, I build an app with a Module using multicore from the ground up. Everything works fine with creating the module through the module manager and the core if I never plan to remove the module's core.  However, what is interesting is once I place the removal call in my code (it doesn't have to get called) then I get the error. (And the error is thrown when the module is attached to the display... weird).

So I downloaded the GarbageCollectingPipes example and found the same error being thrown, but commenting out the remove core in the command does not have the same effect.  I'm now playing with that project to see if I can isolate what is triggering the error.

Does anyone have a clue as to a workaround for this?  I don't wish to downgrade my project to 3.x. 


Thanks!
Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #1 on: August 16, 2010, 07:16:01 »

Not really sure how removeCore could cause UIComponent to throw an error. It does nothing more than remove instances from maps in the Facade, Model, View and Controller.

Facade.as:
:
        /**
         * Remove a Core.
         * <P>
         * Remove the Model, View, Controller and Facade
         * instances for the given key.</P>
         *
         * @param multitonKey of the Core to remove
         */
        public static function removeCore( key:String ) : void
        {
            if (instanceMap[ key ] == null) return;
            Model.removeModel( key );
            View.removeView( key );
            Controller.removeController( key );
            delete instanceMap[ key ];
        }

Model.as
:
        /**
         * Remove an IModel instance
         *
         * @param multitonKey of IModel instance to remove
         */
        public static function removeModel( key:String ):void
        {
            delete instanceMap[ key ];
        }

View.as:
:
        /**
         * Remove an IView instance
         *
         * @param multitonKey of IView instance to remove
         */
        public static function removeView( key:String ):void
        {
            delete instanceMap[ key ];
        }

Controller.as
:
        /**
         * Remove an IController instance
         *
         * @param multitonKey of IController instance to remove
         */
        public static function removeController( key:String ):void
        {
            delete instanceMap[ key ];
        }

I would suggest using your debugger to put a breakpoint at the removeCore call and step through until you find out what's happening. I think it must be something you're doing prior to or subsequent to the call.

-=Cliff>
Logged
gohloum
Jr. Member
**
Posts: 16


View Profile Email
« Reply #2 on: August 16, 2010, 08:12:01 »

Hey Cliff,

Can you try running the GarbageCollectingPipes project example in Flex 4.x?  That project throws the same error as mine.

I have some time today, so I am going to build a minimalist module project and see what I find.  I will post it as soon as I have something to report.
« Last Edit: August 16, 2010, 08:36:13 by gohloum » Logged
gohloum
Jr. Member
**
Posts: 16


View Profile Email
« Reply #3 on: August 16, 2010, 10:18:45 »

OK, so I built a project to test the issue.  I didn't include pipes, but just bubbled an event on the display to keep the code as simple as possible.

The only addition to the code is the KapIt console for monitoring the framework. Shift+alt+Click will open the console.

To my suprise, initially, everything worked just fine.  However, it wasn't until I started messing with the static Facade.hasCore() that I saw the UIComponent error again.  With a little experimentation, I was able to find what conditions would cause the error using the method and which would work as expected.

What I found was  if I test for the module core existence from the shell (calling Facade.hasCore(MyModule.NAME) on Shell.mxml line 53, the UIComponent class throws the error.

:
private function loadModule(e:MouseEvent):void
{
if (moduleContainer.numElements == 0)
{
// Testing to see if core exists here causes UIComponent error
trace("Module Core Exists:", Facade.hasCore(MyModule.NAME))
moduleInfo = ModuleManager.getModule("module/MyModule.swf");
moduleInfo.addEventListener(ModuleEvent.READY, moduleReadyHandler);
moduleInfo.load();
}
}

However, if I performed the same hasCore test from within the module on line 27 - trace(Facade.hasCore(NAME)), then no error is thrown:

:
public static const NAME:String = 'MyModule';

private function init():void
{
// testing to see if the core exists here works fine.
trace(Facade.hasCore(NAME));
ModuleFacade.getInstance(NAME).startup(this);
}

So, here is where my lack of computer sciene knowledge may be my problem:

Since Facade.hasCore() is a static function, then I would personally think it's not scope specific and could be called from anywhere in the application.  However, it would appear that I am observing a scope specific behavior in that I can't test for the existence of a module core from the shell.

Could someone clarify what is suppose to happen and is the error on my end from lack of understanding or something else?

I posted the project on my server.  It's a zip, but just extract and you will find the .fxp inside and use File->Import to bring it into your workbench.

http://67.239.69.29/Testing/ModuleTest.zip

Thanks!
Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #4 on: August 17, 2010, 07:34:18 »

Thanks for taking the time to create the test project to frame the issue.

The problem is you are referencing a constant defined in the not-yet-loaded module when you do this:

:
trace("Module Core Exists:", Facade.hasCore(MyModule.NAME))   

You get no error if you do the equivalent using a string literal:

:
trace("Module Core Exists:", Facade.hasCore("MyModule"))   

Also, note that this problem has nothing to do with PureMVC. You can get the same error by simply doing this at the same point:

:
trace(MyModule.NAME)
Though it seems a bit wonky to me that this actually causes a runtime error.

You don't want to reference NAME or any other constant defined in the module because when you do that, you end up linking the class from the module into the shell, defeating the purpose of doing a loaded module to begin with[1]. FlashBuilder will give you this message if you try to reference that in anything other than a trace:

module:MyModule is a module or application that is directly referenced. This will cause module:MyModule and all of its dependencies to be linked in with Shell. Using an interface is the recommended practice to avoid this.

When you want to share constants between various modules and the shell, you should create a separate library to put those constant definitions in, and then include the library in the shell and any modules that need it.

-=Cliff>

[1] I realize that in the demos such as PipeWorks[2] and Sea of Arrows Player[3] I have referenced the constant NAME from the module in the shell, but in both cases, the modules and the shell are all compiled into the final application and no module loading takes place; the modules are merely instantiated and plumbed. If the modules are to be compiled separately and loaded, then moving shared constants to a library is an important practice.

[2] PipeWorks - http://trac.puremvc.org/Demo_AS3_MultiCore_Flex_PipeWorks
[3] Sea of Arrows Player - http://seaofarrows.com/srcview/
Logged
gohloum
Jr. Member
**
Posts: 16


View Profile Email
« Reply #5 on: August 17, 2010, 12:29:22 »

When you want to share constants between various modules and the shell, you should create a separate library to put those constant definitions in, and then include the library in the shell and any modules that need it.

OK.  So I would like to use the library approach, but not sure I understand what you mean by 'library'.  Would the below code be considered implementation of suggested 'library'?

:
package common
{
/**
* ...
* @author TJ Jones
*/
public class ModuleLibrary
{
public static const MY_MODULE:String = 'my_module';
public static const MODULE_A:String = 'module_b';
public static const MODULE_B:String = 'module_c';

public function ModuleLibrary()
{

}

}

}

And thus the Facade.getInstance() would then be passed the correct constant accordingly?

:
// somewhere in a module initialization....
MyModuleFacade.getInstance(ModuleLibrary.MY_MODULE).startup(this);

I'm all about adhering to best practices whenever possible or suggested, so I'd like to follow your library advice.

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



View Profile WWW Email
« Reply #6 on: August 18, 2010, 07:40:06 »

A library is a separate project, compiled to a SWC and then included in both the module project(s) and the application project. If you're using FlexBuilder then you can just create a Flex Library Project.

When doing a modular project where you're loading the modules, it's a good idea to have the shell and the modules in separate Flex projects. Then you are pretty much insured that you won't accidentally form any dependencies between the modules and the shell.

So, three projects minimum: Shell, Module and Shared Library.

In the shared library, you can add interfaces, constants, value objects, etc. Basically anything that the shell and module both need.

-=Cliff>
Logged
gohloum
Jr. Member
**
Posts: 16


View Profile Email
« Reply #7 on: August 19, 2010, 06:30:53 »

Thanks for all the help and advice Cliff.  I spent the end of my work day and part of my evening at home implementing what you just described in a current project I am working on.  Everything seems to load and unload nicely, memory size drops on unload of module and core, and the KapIt console is confirming that the mediators and proxies are being removed as they should.

Many thanks to your for not only the framework, but taking time to support our issues and questions in the forum.  Time-wise, I know that can be a real undertaking, so I just wanted you to know I really appreciate it.

Thanks again!

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



View Profile WWW Email
« Reply #8 on: August 19, 2010, 08:25:26 »

No problem. Glad to hear you were able to see some joy quickly.

-=Cliff>
Logged
Pages: [1]
Print