Previous Page
Next Page

Recipe 1.17. Handling Errors

Problem

You want to programmatically detect when certain errors occur and handle them using code.

Solution

Use a throw statement to throw an error when it is detected. Place any potentially error-generating code within a try block, and then have one or more corresponding catch blocks to handle possible errors.

Description

Flash Player 8.5 supports a try/catch methodology for handling errors in ActionScript. That means you can write code that can intelligently deal with certain error types should they occur. While you cannot handle syntax errors (the .swf won't even compile in that case), you can handle most other error types, such as missing or invalid data. The benefit is that you can attempt to resolve the situation programmatically.

An example may help to illustrate when and how you might use try/catch methodology: Consider an application that draws a rectangle based on user-input dimensions. To draw a rectangle within the application, you want to have certain range limitations on the dimensions the user can input. For example, you may want to make sure the values are defined, valid numeric values greater than 1 and less than 200. While there are certainly ways you can work to ensure the quality and validity of the data before even attempting to draw the rectangle, you can also use try/catch methodology as a fail-safe. You can have Flash attempt to draw the rectangle, but if the dimension values are detected to be invalid or out of range, you can throw an error that can be handled programmatically. At that point you can do many things, from simply skipping the action, to substituting default data, to alerting the user to enter valid data.

There are two basic parts involved in working with errors in ActionScript: throwing the error and catching the error. There are several errors, which are thrown automatically by the player, such as IllegalOperationError, MemoryError, and ScriptTimeoutError. These are in the flash.errors package. But you can also detect when an error has occurred and throw your own custom error. You can throw an error using the throw statement. The throw statement uses the throw keyword followed by a value or reference that should be thrown. Most frequently you should throw an Error object or an instance of an Error subclass. For example:

throw new Error("A general error occurred.");

As you can see, the Error constructor accepts one parameter, a message to associate with the error. The parameter is optional, and depending on how you are handling the errors, you may or may not choose to use it. However, in most cases it makes sense to specify an error message. It is possible, then, to log the error messages for debugging purposes.

Once an error has been thrown, Flash halts the current process and looks for a catch block to handle the error. This is where the try and catch blocks come into play. Any code that could potentially throw an error should be enclosed in a try block. Then, if an error is thrown, only the code in the try block is halted, and the associated catch block is called. The following is the simplest scenario:

try {
  trace("This code is about to throw an error.");
  throw new Error("A general error occurred.");
  trace("This line won't run");
}
catch (errObject:Error) {
  trace("The catch block has been called.");
  trace("The message is: " + errObject.message);
}

The preceding code produces the following in the Output panel:

This code is about to throw an error.
The catch block has been called.
The message is: A general error occurred.

Of course, the preceding example is overly simplistic, and you wouldn't realistically use code in an actual application, but it does illustrate the basic process. You can see that as soon as the error is thrown, the try block is exited, and the catch block is run and passed a reference to the Error object that was thrown.

Much more frequently, the error is thrown from within a function or method. Then Flash looks to see if the throw statement within the function is contained within a try block. If so, it calls the associated catch block as you've seen already. However, if the throw statement in the function is not within a try block, Flash exits the function and next looks to see if the function call was made within a try block. If so, it halts the code in the try block and runs the associated catch block. Again, a very simple example:

private function displayMessage(message:String):void {
  if(message == undefined) {
    throw new Error("No message was defined.");
  }
  trace(message);
}

try {
  trace("This code is about to throw an error.");
  displayMessage(  );
  trace("This line won't run");
}
catch (errObject:Error) {
  trace("The catch block has been called.");
  trace("The message is: " + errObject.message);
}

In the preceding example the Output panel would display the following:

This code is about to throw an error.
The catch block has been called.
The message is: No message was defined.

As you can see from the output, the code works very similarly to the way in which the previous example worked, except the throw statement is hidden within a function instead of being called directly within the try block. The advantage is that you can start to then create functions and methods that are intelligent enough to know if and when to throw errors. You can then simply use those functions and methods within try blocks, and you can handle any errors should they occur.

The following code illustrates a more realistic example:

// Define a function that draws a rectangle within a specified sprite
private function drawRectangle(sprite:Sprite, newWidth:Number, newHeight:Number):void {

  // Check to see if either of the specified dimensions are not 
  // a number. If so, then thrown an error.
  if(isNaN(newWidth) || isNaN(newHeight)) {
    throw new Error("Invalid dimensions specified.");
  }

  // If no error was thrown, then draw the rectangle.
  sprite.graphics.lineStyle(1, 0, 1);
  sprite.graphics.lineTo(nWidth, 0);
  sprite.graphics.lineTo(nWidth, nHeight);
  sprite.graphics.lineTo(0, nHeight);
  sprite.graphics.lineTo(0, 0);
}

Now we can call the drawRectangle( ) method using a try/catch statement.

try {

  // Attempt to draw two rectangles within the current sprite. 
  // In this example it is assumed that the variables for the dimensions 
  // are retreiving values from user input, a database, an XML file, 
  // or some other datasource.
  drawRectangle(this, widthA, heightA);
  drawRectangle(this, widthB, heightB);
}
catch(errObject:Error) {

  // If an error occurs, clear any rectangles that were drawn from 
  // the sprite. Then display a message to the user.
  this.graphics.clear(  );
  tOutput.text = "An error occurred: " + errObject.message;
}

In addition to the try and catch blocks, you can also specify a finally block. The finally block contains code that is called regardless of whether an error was thrown. In many cases the finally block may not be necessary. For example, the following two examples do the same thing:

//Without using finally:
private function displayMessage(message:String):void {
  try {
    if(message == undefined) {
      throw new Error("The message is undefined.");
    }
    trace(message);
  }
  catch (errObject:Error) {
    trace(errObject.message);
  }
  trace("This is the last line displayed.");
}
//With finally:
private function displayMessage(message:String):void {
  try {
    if(message == undefined) {
      throw new Error("The message is undefined.");
    }
    trace(message);
  }
  catch (errObject:Error) {
    trace(errObject.message);
  }
  finally {
    trace("This is the last line displayed.");
  }
}

However, the finally block runs no matter what occurs within the try and catch blocks, including a return statement. So the following two functions are not the equivalent:

//Without using finally:
private function displayMessage(message:String):void {
  try {
    if(message == undefined) {
      throw new Error("The message is undefined.");
    }
    trace(message);
  }
  catch (errObject:Error) {
    trace(errObject.message);
    return;
  }
  // This line won't run if an error is caught.
  trace("This is the last line displayed.");
}
//With finally:
private function displayMessage(message:String):void {
  try {
    if(message == undefined) {
      throw new Error("The message is undefined.");
    }
    trace(message);
  }
  catch (errObject:Error) {
    trace(errObject.message);
    return;
  }
  finally {
    // This runs, even if an error is caught.
    trace("This is the last line displayed.");
  }
}

You can create much more complex error handling systems than what is shown in this recipe. Throughout this book you will find examples of more complex error handling in appropriate contexts.


Previous Page
Next Page
Converted from CHM to HTML with chm2web Pro 2.85 (unicode)