Why isn't this garbage collected - actionscript-3

If I make a timer such as
var timer:Timer = new Timer(50, 0);
timer.addEventListener(TimerEvent.TIMER, OnTimer);
timer.start();
and then my function ends, you would think this timer has gone out of scope and nothing is holding on to a reference of it anymore. However this timer still works.
So either I am getting lucky and the garbage collector hasn't run yet or something is holding on to a reference. If it is the latter then how will I know it is going to be garbage collected?

Timer will still run and will be dispatching events. Just declare it the way you can access it (as public instance variable) and perform:
timer.stop();
timer.removeEventListener(TimerEvent.TIMER, OnTimer); - VERY important thing in Flash
timer = null; - if you really need to free memory, set the reference to null

Related

TimerEvent function ignoring Timer delay

I'm working in AS3, Flash AIR 3.2 for iOS SDK. I'm trying to run part of the program only after myLoader finishes loading an image. I have a myTimer.start(); which runs inside myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoaderComplete);.
What seems to be the problem at the moment is that the program is ignoring the 1000ms. The program is running after myLoader is finished at the moment, but it just seems to be doing its own thing in terms of the delay.
EDIT: Being more precise here... The program seems to be ignoring the Timer delay. Even if Timer is set to 100000ms. It seems to be running the rest of the program right after the image is loaded.
EDIT: I still had my methods running inside my Main() as well as the timerListener() in the code. Thought I commented them out. Whoops!
var myTimer:Timer = new Timer(1000);
public function Main()
{
init();
displayImage();
myTimer.addEventListener(TimerEvent.TIMER, timerListener);
myTimer.addEventListener(TimerEvent.TIMER_COMPLETE, timerDone);
}
public function displayImage():void {
myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoaderComplete);
myLoader.load(fileRequest);
}
public function onLoaderComplete(e:Event) {
//start Timer event here
myTimer.start();
}
public function timerListener (e:TimerEvent):void{
trace("Timer is Triggered");
myTimer.stop();
aMethod();
anotherMethod();
moreMethods();
}
You don't really clarify what you mean by "the timer is doing its own thing." Is the timer shorter or longer than you expect?
What I think is likely going on here is that your timer tick and your frame rate are out of synch. If you're familiar with the concept of the elastic racetrack, you know that the single-threaded nature of Flash (unless you're using worker threads) means that the screen can't update during a script and vice-versa. This means that if your Timer fires while the Display list is updating, it just has to wait until the display list finishes and may even have to wait until other scripts have run, depending on how Flash is prioritizing the different things in its queue.
From the Timer API:
Depending on the SWF file's framerate or the runtime environment
(available memory and other factors), the runtime may dispatch events
at slightly offset intervals. For example, if a SWF file is set to
play at 10 frames per second (fps), which is 100 millisecond
intervals, but your timer is set to fire an event at 80 milliseconds,
the event will be dispatched close to the 100 millisecond interval.
Memory-intensive scripts may also offset the events.

Do AS3 socket event listeners require function scope where they are defined to end?

Say we have a function and a socket declared in it. We called connect on it. Now we called addEventListener on to connect.
In theory we could set function provided to eventDispatcher to change a class variable while a function that originally called addEventListener could be locked on that variable (alike while(!class_instancce.is_connected)).
My question is: will function passed to addEventListener be called of flash run time will wait for a function that is "on wait" to end?
The function that is passed to addEventListener will run as soon as whatever event you're listening for is dispatched by the instance you're listening to (if there are multiple listeners, this will be based on event priority.
It sounds to me like you want to try to make the socket connection happen synchronously. You can't do this with sockets, though there are some things in AS that you can force to be synchronous.
Honestly, you should get comfortable with event-driven architecture sooner rather than later, because it makes all sorts of OOP loveliness possible for you.
You can use anonymous functions if you're bound and determined. You can research it yourself. I think it's a bad habit unless you really know what you're doing and how to avoid memory leaks, etc.
Here is how sockets work in AS3:
First create the socket and add Listeners:
_socket = new Socket();
// or if secure
_socket = new TLSSocket();
_socket.addEventListener(Event.CONNECT, onConnect);
_socket.addEventListener(ProgressEvent.SOCKET_DATA, onData);
// also add listeners for errors, close etc
_socket.connect(myURL, myPORT);
private function onConnect(event:Event):void{
//connection is live now so do whatever like send something
var request:String = "create a request here";
_socket.writeUTFBytes(request);
_socket.flush();
}
private function onData(event:ProgressEvent):void{
//this gets called EVERY time new data comes over the socket
// the socket will stay connected until you close it (or an error makes it drop)
// here is how you read what came over the socket
while(_socket.bytesAvailable){
theData = _socket.readUTFBytes(_socket.bytesAvailable);
}
// now do something with the data
}
Hope that helps you with getting your sockets set up

as3 air unloadAndStop() event listener or timer

my air application plays an external swf over and over until time to play the next external swf. in order to avoid memory leaks i am using unloadAndStop(). i am using two timers. the first unloadAndStops the swf. the second waits two seconds then loads it back up again.
this approach (coupled with the use of weak references) seems to keep the memory in check. however, i'd rather not use timers but event listeners. is there an event listener for when unloadAndStop completes to then load the swf again.
here is what i had in mind:
var TIMER_INTERVAL:int = int(duration);
var t:Timer = new Timer(TIMER_INTERVAL);
t.addEventListener(TimerEvent.TIMER,updateTimer,false,0,true);
t.start();
private function updateTimer(e:TimerEvent):void
{
swfLoader.unloadAndStop(true);
swfLoader.addEventListener(Event.UNLOAD,onSWFUnloadComplete,false,0,true);
}
private function updateTimer(e:TimerEvent):void
{
var swfSource2:String = File.applicationStorageDirectory.nativePath.toString();
swfLoader.load(swfSource2+'\\'+name_xml);
}
unloadAndStop is not an asynchronous method, so an unload event wouldn't really be relevant. What is likely happening behind the scenes is that it takes 1 full frame to fully dispose of the movies objects/listeners and that's why you're having issues loading it again in the same block of code.
If you wait just one frame before loading it again, you should have the results you expect.
Now, of course the best solution is go into the source file of your loaded swf and fix the memory leaks.

How do I completely remove a loaded swf and reload it? (Trying to restart a game)

I have a preloader that loads a swf, the swf creates a bunch of listeners, objects, and movie clips. I want all of these to be destroyed and recreated.
Simplified version of my preloader:
var request:URLRequest = new URLRequest("myfile.swf");
var myLoader:Loader = new Loader();
var urlLoader:URLLoader = new URLLoader();
urlLoader.addEventListener(Event.COMPLETE, function(event){
stage.addChild(myLoader);
myLoader.loadBytes(urlLoader.data);
});
urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
urlLoader.load(request);
When I try to remove it, I do this:
stage.removeChild(myLoader);
var child = loader.myLoader.content as Object;
SoundMixer.stopAll();
while(stage.numChildren > 0){
stage.removeChildAt(0);
}
child.stop();
while(stage.numChildren > 0){
stage.removeChildAt(0);
}
child=null;
System.gc();
myLoader.unloadAndStop(true);
System.gc();
myLoader.unload();
System.gc();
myLoader.loadBytes(urlLoader.data);
stage.addChild(loader.myLoader);
In your loaded SWF you may create a method 'destroy' which would remove all listeners, destroy all objects and reset all data.
You can call this method either from the parent object (if the method is public) or you can call destroy when you remove the SWF from stage (Event.REMOVED_FROM_STAGE)
You can reload swf with js, this is the easy way to do this. you can check this answer.
Or you have to do a good object and listener managment and reset game in swf file. This might be complex as project get bigger. You need release methods that removes all references and listener.
first you should load your swf using the Loader Class like this :
var movie:MovieClip
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadComplete);
loader.load( new URLRequest("myfile.swf"));
function loadComplete(event:Event):void
{
movie = loader.content as MovieCLip;
addChild(movie);
}
//when reloading just remove the movie object from the stage
removeChild(movie);
SoundMixer.stopAll();
//......
//.
//.
I know this is old, but I stumbled on it for reference and see some things that I think should be mentioned.
System.gc() - while it's a function you have access to, everything I've seen suggests that the garbage collector should never be called by your code unless you've used a considerable amount of memory and need it back immediately. The garbage collector usually has a better idea of when it should run than you do (Force Garbage Collection in AS3?). It can impact performance for not just your application but all flash applications running in that browser or container.
There's also a good bit of people struggling to make effective use of unloadAndStop(), as it seems to be rather unreliable in various contexts (Unloading swf using the unloadAndStop() method, but video sounds remain audible).
To be thorough, I'd strongly suggest putting the effort into simply eliminating everything as it would be in any other language from within the loaded flash object first before removing the flash object itself, not expecting the container to take care of it for you. This is why Flash has a reputation for memory leaks to begin with.
Inside the loaded swf, add code that fires on unload.
One way is to add this to the swf:
this.addEventListener(Event.REMOVED_FROM_STAGE, doUnload)
Then have the doUnload functon perform the following:
Use removeEventListener to effectively terminate the event handlers. You could either recall all the addEventListeners you created, or cook up a routine to walk through and remove them all by traversing the objects in play. The first option is more efficient since it's exclusive, but the second option would theoretically be something you could memorize and copy between applications.
Use delete() on variables to make them removable by the garbage collector. NOTE: Unlike many languages, a referenced variable will not be removable unless the reference is also removed. For example:
var a:int = 0;
var b:int = a;
delete(a); // b still exists and equals 0, a is not available to GC.
delete(b); // now both variables can be removed by GC.
There's also still confusion as to whether it's a good idea to use removeChildAt(0) or remove the child objects individually. The first has the benefit of being distinctly simple and straight-forward, but that also gives it the caveat of not being entirely understood by the coder, and possibly missing something similarly to unloadAndStop(). Not as much as walking your object tree with removeChild and eliminating things explicitly without question or uncertainty.
After this is set, adding a function to unload the flash object will trigger its self-removal, so the loader will remain simple and neat, and reload the flash cleanly.

ActionScript 3: Measuring elapsed time between enterFrame events

I have an EnterFrame event, and I want to know the exact time between calls, so I will be able to animate objects more smoothly when the computer can't produce the desired framerate.
To be a little more specific.
currentTime = getTimer();
diff = currentTime - prevTime;
prevTime = currentTime;//update for next go around
EDIT
getTimer requires you import the package: flash.utils.getTimer;
use getTimer(); ?
as the others stated, getTimer is the best way to go ... but i wanted to suggest something else:
if you want to do time based animation, that are updated frame based, you might also try some of the bigger ActionScript tweening libraries, as the caurina Tweener ... they simply do that out of the box and provide other great features ...
greetz
back2dos
You should use the inbuilt Timer function to call a method at a somehow* ENTER_FRAME independent way.
var timer:Timer = new Timer(500, 0);
timer.addEventListener(TimerEvent.TIMER, timerHandler);
timer.start();
private function timerHandler(event:TimerEvent):void
{
// do something
// *EDIT* Thanks #Luke spotting this out (check comments)
event.updateAfterEvent();
}
*) Still you need to keep in mind the event handler will not be triggered between frames so in case your script is lagging (because of some other process) this call will also be delayed.
To be precise, the method call will be approximated at the frame executed at the same time or right after the set delay time.