Split is not a function? - actionscript-3

I have this code I was testing with:
var test:String="Hello there; im zane"
var parts:Array=test.split(";");
trace(parts)
trace(parts[0])
var randomnum:Number=0;
stage.addEventListener(Event.ENTER_FRAME, code)
function code(c:Event):void{
if(parts[randomnum] != undefined && parts[randomnum] != null){
parts[randomnum]=parts[randomnum].split(" ");
randomnum+=1
trace(parts[randomnum])
}
else{
randomnum=0
}
}
And there is an error with this parts[randomnum]=parts[randomnum].split(" ");. Flash says that split is not a function (
TypeError: Error #1006: split is not a function.
at Untitled_fla::MainTimeline/code()
)
Earlier in this project, I used the split function with a different part of the variable, and I also tried parts[0]=parts[0].split(" ") out of the event and it worked fine.
What I'm trying to find out is, why does a split command not work in this scenario? Am I doing something wrong?

I also tried parts[0]=parts[0].split(" ") out of the event and it worked fine.
Even outside of the event, this line doesn't make much sense, because it assigns the return value of split() to the same variable that the method was invoked on. As the ENTER_FRAME is repeatedly executed, this fails on the second time it happens, because split() returns an Array which has no such method itself, which is what the error is basically saying.

Related

AS3 Asynchronism problems

I had a strange bug in my program which I fortunately found quite quickly but am still puzzled why it was happening. Essentially it was to do with the order of commands in the source code and event listeners, here is the example:
function detectFaces(loader:ImageLoader)
{
var detector:FaceDetector=new FaceDetector();
detector.addEventListener(FaceDetectorEvent.FACE_CROPPED,facesDetected);
detector.loadFaceImageFromBitmap(loader.bitmap);
var something:Number = stage.width;
function facesDetected(e:FaceDetectorEvent):void{
trace(something);
}
}
Operation that raise the event here is not important, only thing to note about it would be it takes around 100ms. What I get as trace output is NaN and I don't know why that is since line declaring the variable something will definitely be called before callback of facesDetected and it is in scope of the handler function declared under it. This problem was easy to solve by just moving var something:Number = stage.width; before loadFaceImageFromBitmap(..) method, but I would really like to know why this is happening?
I am suspecting this is not due to order of execution but has something to do with passingByValue and passingByRefrence deferences but don't know how would these cause an error like this.
EDIT: Now I am even more puzzled... This code works in any order of declaration:
timers();
function timers()
{
var timerTest:Timer = new Timer(100,1);
timerTest.addEventListener(TimerEvent.TIMER,onTime);
//BEFORE DECLARATION
timerTest.start();
var something:Number = stage.width;
function onTime(e:Event)
{
trace("SOMETHING :"+something);
}
}
timers();
function timers()
{
var timerTest:Timer = new Timer(100,1);
timerTest.addEventListener(TimerEvent.TIMER,onTime);
var something:Number = stage.width;
//AFTER DECLARATION
timerTest.start();
function onTime(e:Event)
{
trace("SOMETHING :"+something);
}
}
With regard to your initial question, actionscript will complete the execution of a block of code before it continues to execute subsequent lines. If there was nothing asynchronous happening in your loadFaceImageFromBitmap method (ie, if your weren't using a Loader or some other object that had to wait for an event to fire) then, however long the code takes to execute, the FACE_CROPPED event will still fire before 'something' is set to a value.
As for the other problem, it looks to me like the answer is simply that you're using a TimerEvent - Actionscript will acknowledge that it shouldn't wait for the event to fire before continuing to execute code; It will, therefore, declare 'something' before the 100 miliseconds passes. So, in this case, because you're using an event, the code WILL continue 'reading' and executing the lines following the event listener.
The code of the function loadFaceImageFromBitmap run on a sync way. The FaceDetectorEvent.FACE_CROPPED event listener is invoked inside of that function, it is not a callback declared to run after some response is returned for ie(http request).
In the case of the Timer it works as expected, because event listener is not invoked right at the start moment, it waits for X time.

ActionScript 3 isn't supposed to be a simple synchronous architecture language?

A simple piece of code that should trace :
rien
test
done!
and I get something completely far away from that,
scenario A :
var __functions_to_execute:Array;
function start():void {
__functions_to_execute =[];
__functions_to_execute.push(futile_trace());
__functions_to_execute.push(futile_trace('test'));
execute_functions();
}
function execute_functions():void {
if(__functions_to_execute.length){
//where shift on this Array remove the first element and returns it
var exec:Function =__functions_to_execute.shift();
exec;
//I tried this too, just in case
//__functions_to_execute[0];
//__functions_to_execute.shift();
} else trace("done!");
}
function futile_trace(_value:String ='rien'):void {
trace(_value);
execute_functions();
}
start();
pretty simple. but the result is :
rien
done!
test
lets add a deprecated function to this and lets change the futile_trace function to :
function futile_trace(_value:String ='rien'):void {
trace(_value);
setTimeout(execute_functions, 0);
}
and then the result is :
rien
test
done!
Ok then, I said to myself, why not, lets change the scope when I call execute_functions, so I tried :
function futile_trace(_value:String ='rien'):void {
trace(_value);
extra_step();
}
function extra_step():void {
execute_functions();
}
guess what was the result?! yeah :
rien
done!
test
so?! Is the trace function that bad? that slow? is it the fact that passing an argument to the function take so much time compare to the other one? I mean... wow!
is there something I can do to avoid this type of weirdness ?
(For the record, my project is not to trace {rien, done and test}... I have 15k lines of codes that react completely differently if I compile them with "Omit trace statements" or not.
Thanks for your input guys.
You are executing the functions and adding their return values to the __functions_to_execute array, not the functions themselves.
Your function execute_functions doesn't actually do anything. I've tried to explain the sequence in-line:
function start():void {
__functions_to_execute =[];
// 1. traces 'rien' first because futile_trace() is called with no args
// 2. 'done!' will be traced inside execute_functions because the array is still empty
// 3.undefined will be pushed into the array next
__functions_to_execute.push(futile_trace());
// 4. traces 'test'
// execute_functions does not trace anything because __functions_to_execute is non-empty
// but it also doesn't do anything because it is just removing the `undefined` value from the start of the array.
__functions_to_execute.push(futile_trace('test'));
execute_functions();
}
Something more like this should behave how you expect. It's storing in the array function references, along with the arguments that should be passed when the function is called.
var __functions_to_execute:Array;
function start():void {
__functions_to_execute = [];
__functions_to_execute.push({func:futile_trace, args:[]});
__functions_to_execute.push({func:futile_trace, args:['test']});
execute_functions();
}
function execute_functions():void {
if(__functions_to_execute.length){
var obj:Object = __functions_to_execute.shift();
obj.func.apply(null, obj.args);
} else trace("done!");
}
function futile_trace(_value:String ='rien'):void {
trace(_value);
execute_functions();
}
start();
For scenario A, you're not actually ever pushing futile_trace to the array - you're calling it (notice the () after the function name), and then pushing the result of that call to the array.
In other words:
You call futile_trace()
futile_trace traces 'rien', because you passed no value.
futile_trace calls _execute_functions
At this point, nothing has been pushed yet, so _execute_functions traces 'done!'
_execute_functions returns.
_futile_trace returns.
The result of futile_trace() (void) is pushed.
You call futile_trace('test')
futile_trace() outputs 'test'.
futile_trace calls _execute_functions
_execute_functions shifts void from the array.
_execute_functions executes void; (which does nothing)
etc. etc.
If you need to pass a function to another function or store a reference to it in a variable, make sure you're not calling it.
__functions_to_execute.push(futile_trace);
// Use an anonymous function to pass with arguments without executing:
__functions_to_execute.push(function() { futile_trace('test'); });
... and in _execute_functions do remember the parantheses:
exec();

Can't remove child from the stage - if(stage.contains(child1)){removeChild(child1);} doesn't work

It may sound stupid, but how can I remove a definite child from the stage?
e.g.
function giveMeResult(e:MouseEvent):void
{
if(stage.contains(result))
{removeChild(result);}
addChild(result); // this part works fine, but it adds one over another
}
it adds one result on the top of the previous one.
I want the function "giveMeResult: to remove "result" if is on the stage and add a new one.
UPDATE:*
result is a TextField, and result.txt ="" changes from time to time ...
trace (result.parent); /// gives [object Stage]
trace (result.stage); /// gives[object Stage]
trace (result.parent != null && result.parent == result.stage); // gives true
when
result.parent.removeChild(result);
is written without if statement - gives error TypeError: Error #1009: Cannot access a property or method of a null object reference.
when written inside:
if (result.parent !=null && result.parent == result.stage)
{
result.parent.removeChild(result);
}
nothing happens and new child is added on the top of the previous one.
Thanks to all!!!
The result is simple :)
All I had to do is just change result.txt without even removing it from the stage :)
You need to type stage.removeChild(result); and subsequently stage.addChild(result);
Edit:
Looking at a function similar to yours:
private function func(e:Event) : void {
if(stage.contains(result)) {
stage.removeChild(result);
}
stage.addChild(result);
}
The only way this would add a new instance of the TextField result to the stage, without removing the old one, would be if result has changed. See this flow of execution:
var result : TextField = new TextField();
// An event occurs and func get's called.
// now result will be added to stage.
result = new TextField();
// An event occurs and func get's called again
// This time the stage.contains(..) will return false, since the current result
// is not actually on stage. This will add a second TextField to the stage.
If I am clearly understood what you want, then this code can help you:
if (result.parent != null && result.parent == result.stage)
{
// stage itself contains result
result.parent.removeChild(result);
}
From the docs for DisplayObjectContainer.contains(): "Grandchildren, great-grandchildren, and so on each return true."
So contains means anywhere on the display list, not just direct children. What you want is the parent check Manque pointed out, or simply to remove result from anywhere it might be:
if (result.parent) {result.parent.removeChild(result); }
Though oddly, addChild(result) will automatically remove it from its previous parent - a DisplayObject can only be at one place in the DisplayList at a time, so I'm not sure why you're seeing multiple results...
Is it possible that the "result" you've passed in isn't the result that's already on the stage?
Have you tried?
MovieClip(root).removeChild(result)
[EDIT]
function giveMeResult(e:MouseEvent):void{
if(result.parent != null && result.parent == result.stage){
stage.removeChild(result);
}
stage.addChild(result);
}
All I had to do is just change result.txt without even removing it from the stage

Passing e:MouseEvent as an argument via setInterval

So i have this function
capture_mc.buttonMode = true;
capture_mc.addEventListener(MouseEvent.CLICK,captureImage);
function captureImage(e:MouseEvent):void {
//lalalala
}
I want to call this function every 2 seconds (after mouse click event happens).
I tried using setInterval
setInterval(captureImage,2000,e:MouseEvent);
but it leads to following error
1084: Syntax error: expecting rightparen before colon.
What's wrong ?
And ya, i am new to AS.
First, since this is AS3 you should be using Timer and TimerEvent. I'll show you how in the example.
Now you'll need to separate your functions:
edit: I've updated this to be safer based on #(Juan Pablo Califano) suggestions. I would keep the same timer for ever if the amount of time isn't going to change.
// first param is milliseconds, second is repeat count (with 0 for infinite)
private var captureTimer:Timer = new Timer(2000, 0);
captureTimer.addEventListener(TimerEvent.TIMER, handleInterval);
function handleClick(event:MouseEvent):void
{
// call here if you want the first capture to happen immediately
captureImage();
// start it
captureTimer.start();
}
function handleInterval(event:TimerEvent):void
{
captureImage();
}
function captureImage():void
{
// lalalala
}
You can also stop the timer with captureTimer.stop() whenever you want.
The problem is that you should use the parameterName:ParameterType syntax only when declaring formal parameters (or when declaring vars and consts). Meaning, this is valid only when you are defining a function:
function func(paramName:Type){
}
When you call the function, you don't have to put the type of the arguments.
So, your function call should look like this:
setInterval(captureImage,2000,e);

Adobe Air, packaged install fails with my trace routine... how come?

I cobbled together some code from here and there for a trace I like... it generates an error to get a stack trace and picks out the traced routine name, I like that detail in the trace log.
Problem: it fails in an installed AIR file. I wonder why? I don't expect it to do anything as is... just, I'd prefer it not cause the program to fail!
tx
artie
enter code here
static public function XTRACE( ... traceArgs ):void {
try {
throw new Error(); // make a stack
} catch (e:Error) {
var stack:String = e.getStackTrace();
var frames:Array = stack.split("\n");
var myFrame:String = String(frames[2]);
myFrame = myFrame.replace("\t", "");
// "at " can be followed by some part of the package
// you don't want to see. E.g., if your code is all in
// com.foo.bar, you can put "at com.foo.bar." so as not
// to crowd the display
myFrame = myFrame.substr("at ".length);
myFrame = myFrame.substring(0, myFrame.indexOf("["));
var now:Date = new Date();
trace(new Date().toLocaleTimeString() + ":" + myFrame + ": " + traceArgs.join(" "));
}
}
In what way is your app failing?
1) Trace routines are for debugging, so your trace won't do anything in an installed app.
2) I'm not sure when you call this routine, but it seems weird that you have a routine that only throws an error. I think in this code the 'catch' is only going to get entered if there's an error throwing the error. Normally you would try to perform some useful action, and catch errors when something goes wrong.
Within the trace function your attempting to invoke the Date().toLocaleTimeString() statically before it becomes instantiated by the new keyword. Try the following instead:
trace((new Date()).toLocaleTimeString() + ":" + myFrame + ": " + traceArgs.join(" "));
thanks for your input Fergal. The XTRACE function works fine running with the debug player, and fails only when running with the release player. So I assume the code line I use must associate values in the right order... I settled on using a function I didn't know about before:
enter code here
static public function XTRACE( ... traceArgs ):void {
if ( Capabilities.isDebugger ) {
With that, XTRACE does nothing unless it is executing in a debug environment. So it works around the issue. I'll still use your brackets though, I like to make order of association obvious too ;-)
I realize you've probably grown old and forgot what flash is since you asked this question. But, you're getting an NPE because e.getStackTrace() returns null in the release player.
A couple other things:
You don't need to throw the error to get a stack trace; new Error().getStackTrace() works fine.
Since this is debug code, and the calling code probably isn't expecting errors, you should wrap the whole thing in a try catch.
The compiler won't resolve 'at '.length, so it will be called every time at runtime. Unless you're really paranoid, you can just hard code it to 3.
Both the substrs can be combined into 1
The now variable isn't used.