Try it, if you dare!

Today, I’m going to talk about the Try…Catch…Finally trio. As developers, we perform all the initial testing on our apps before passing them along to the QA team, or even going live with it, depending on your setup. Even with all these eyes looking at your app, there are still unexpected exceptions that can throw the proverbial monkey wrench in your gears. Catching errors is a process that requires code to be executed and examined before it can actually run.  Your app would need to perform, or “try”, the task before actually executing it, and if no errors are found, it will then go ahead and run it.

TCFBlocks

try
{
//try block
}
catch(error:ErrorType)
{
//catch block
}
finally
{
//finally block
}

The ActionScript Virtual Machine

More and more apps are consuming and aggregating feeds from various web-services and can come across all sorts of unexpected results. There are two version of the AVM2, the Release Version and the Debugger Version, and any AS3 code running in the Debugger Version of the AVM2 will generate an error message if any such exceptions are met. The reason why I bring this up is because many people are running the Debugger Version without even knowing it, perhaps it was installed by their IT team at work or they installed it unknowingly from the Adobe site. Either way, users will see these pesky errors, and it’s not good to say the least.

Flash Error

Sample Flash Error Screenshot

Back in AS2, the AVM1 would simply fail silently without halting your application. This was obviously pleasing from a users standpoint as they had no idea that something had gone wrong. The same was true from a developers standpoint which made it very difficult to find the problem. By no means am I advocating writing bad or loose code, but simply suppressing errors should be your last resort. As a developer we should test all “possible” scenarios before going live with the app. This is where unit testing comes into play, but we’ll talk more about that when the time comes.

Asynchronous Errors

When publishing a new SWF the compiler will indicate all the syntax errors, if any, but it’s when we start loading data or media from external sources – asynchronously – is where these potential run-time errors lie.  And for this reason, we need to try/test the code before and after actually running it. This will not only suppress the error, but handle it accordingly or perform another necessary task or function. A perfect example of this is loading either an image or a feed from an offline server, or the feed URL has changed, or the feed is empty for whatever reason, unfortunately this happens all the time. The code below will attempt to load a file which doesn’t exist and will be caught in an IOError exception case.

var loader:URLLoader = new URLLoader();
loader.addEventListener(IOErrorEvent.IO_ERROR, onDataLoadError);

loader.load(new URLRequest("noFile.xxx"));

function onDataLoadError(error:IOErrorEvent):void
{
loader.removeEventListener(IOErrorEvent.IO_ERROR, onDataLoadError);
trace(error.text);
//Outputs: Error #2035: URL Not Found.
}

Notice that the try catch is nowhere to be found in this example, we could have enclosed one around the loader.load line, but I don’t like that method, I prefer trying on data in hand. In this case, we add an event listener to the loader instance, if we weren’t listening for loader errors, the user would get a nasty error dialog like the one above.

Say we’ve loaded everything just fine and now we want to cast and manipulate the loaded data, but the XML feed happens to be malformed. Sorry to say, but this is also common. A number of things can cause malformed XML, ie. bad XSL, namespace updates, or an unterminated node.

var loader:URLLoader = new URLLoader();
loader.addEventListener(Event.COMPLETE, onDataLoaded);

loader.load(new URLRequest("http://testng.org/testng-1.0.dtd"));

function onDataLoaded(event:Event):void
{
loader.removeEventListener(Event.COMPLETE, onDataLoaded);

try
{
var xml:XML = new XML(event.target.data);
}
catch (error:TypeError)
{
trace(error.message);
//Outputs: Error #1090: XML parser failure: element is malformed.
}
}

The idea here is to enclose suspicious or error-prone code in the try block, to then respond to that error accordingly using the catch block(s). The finally block will contain code which will execute regardless of the outcome, I and just about everybody I know don’t use the finally block just for that reason indicated. Even if you have a return statement to exit the function, the finally block will still run, very useless if you ask me.

Your try block must be followed by either a catch block, a finally block, or both. You can have as many catch blocks as you want, each variable in the catch case must be typed with the appropriate error type and your try blocks can be nested as deep as they have to go. You can also throw a new error which can be caught using the appropriate catch block, this is of course generating an error on your part, and you might ask yourself, “why are we creating errors, isn’t it our job to prevent them”? Well, the short answer is yes, but if an error isn’t caught using the catch block we can generate it to obey the flow of our error trapping mechanism. When using this method, we would need to throw the error as an instance of the Error class or a subclass there of.

Throw Example

function checkEmail(email:String):void
{
if (email.indexOf("@") == -1)
{
throw new Error("Invalid Email Address");
}
}

try
{
checkEmail("bobbyberberyan.gmail.com");
}
catch (error:TypeError)
{
trace(error.message);
//Outputs: Invalid Email Address
}
This entry was posted in Flash AS3, Syntax and tagged , , , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *