Consejo rápido Cómo depurar un error AS3 # 1063

Es hora de otro Consejo rápido de depuración. Continuaremos enfocándonos en errores específicos (y comunes) que tienden a obstaculizar a los ActionScripters menos experimentados. En este caso, cubriremos el Error # 1063, el error de discrepancia en la cuenta del argumento.


Paso 1: ser malo

En primer lugar, vamos a crear una situación donde se produce el error. Abra un nuevo documento de Flash (asumiendo que está siguiendo junto con Flash Pro CS3 +, de lo contrario, esta muestra se adapta fácilmente a un proyecto de Flex). Abra el Editor de Script e ingrese el siguiente código:

 import flash.events.MouseEvent; función onClick (): void trace ("click.");  stage.addEventListener (MouseEvent.CLICK, onClick);

Probablemente puedas detectar el problema ya; si ha pasado mucho tiempo escribiendo ActionScript 3, se habrá encontrado escribiendo controladores de eventos. Si no, no te sientas mal, repasaremos todo a su debido tiempo..

Si ejecuta el archivo Flash tal como está y luego hace clic en el escenario, producirá el siguiente mensaje de error en tiempo de ejecución:

 ArgumentError: Error # 1063: Discrepancia en el recuento de argumentos en Untitled_fla :: MainTimeline / onClick (). Se esperaba 0, se obtuvo 1.

Y nunca llegamos a la declaración de seguimiento que debería han corrido después de hacer clic.


Paso 2: Romperlo

Entonces, ¿qué está pasando? En este caso, la vergüenza de Adobe para el error en realidad no es tan mala, y si te has acostumbrado a analizar un mensaje de error en tiempo de ejecución, su significado podría ser bastante claro. Pero no todos son tan inteligentes como tú, así que aquí está el desglose para todos los demás.

ArgumentError -- Esto es información un tanto intrascendente, pero muestra la información específica. Error clase que fue lanzado. Tenemos algo que no es tan general como un simple Error, y hemos ingresado en una categorización específica de error asociada con argumentos (a funciones y métodos).

Error # 1063 -- Aquí solo damos el número de error formal, como todos los errores de buen tiempo de ejecución. Puede usar este código para ubicarlo más fácilmente en la documentación de error en tiempo de ejecución de Adobe.

Discrepancia en el recuento de argumentos? -- En términos más proletarios, hubo un número incorrecto de argumentos enviados a una función. Cual funcion Sus?

? en Untitled_fla :: MainTimeline / onClick (). -- Esto simplemente identifica la función que recibió el número incorrecto de argumentos.

Se esperaba 0, se obtuvo 1. -- Obtenemos un poco de información adicional en esta descripción del error. Esto detalla el desajuste de la cuenta. Esta frase cambiará de acuerdo con la naturaleza del error específico, pero en nuestro caso dice que la función se escribió sin ningún argumento en la firma, pero se envió un solo argumento de todos modos..

Flash le gusta sus patos en una fila. Por lo tanto, se da cuenta de esta discrepancia y decide lanzar un berrinche error, porque preferiría que usted (el desarrollador) descubriera qué fue lo que salió mal en vez de simplemente ignorar el problema. Esto es bueno, porque si el desajuste en el recuento fue de la otra manera (esperado 1, obtuve 0), entonces estaríamos atascados sin un argumento para un parámetro requerido, y la función lo haría..


Paso 3: La raíz del problema

La naturaleza del error debería ser clara en este punto, pero aún se estará preguntando por qué ocurrió. ¿De dónde vino ese argumento superfluo??

El argumento no es exactamente superfluo. Se espera, en realidad, ya que hemos conectado nuestra función para que sea un oyente de eventos. El sistema de eventos en Flash tiene la noción de un objeto de evento Eso encapsula aspectos del evento que ocurrió. Este objeto se pasa a la función de escucha como único argumento. Así que nosotros esperado 0 porque escribimos nuestra función sin ningún parámetro, pero tengo 1 porque el despachador de eventos enviado a lo largo de un objeto de evento.

Ahora puede que se pregunte por qué el compilador no detectó este error. Es cierto: si escribiste esto:

 función sayClick (): void trace ("click.");  sayClick (42);

Entonces el SWF ni siquiera se compilará, porque obtendrás este error:

 1137: Número incorrecto de argumentos. No se espera más de 0.

La diferencia es que en el último ejemplo, tenemos un código real que llama a la función con el número incorrecto de argumentos. Es decir, escribimos la línea hacia abajo que llama a la función incorrectamente. El compilador puede mirar la línea que define la función y la línea que llama a la función, compararlas en busca de discrepancias y hacer sonar la alarma cuando ocurran..


Imagen de Alan / Falcon

Sin embargo, en el ejemplo original, no hay una línea de código escrita que literalmente llame a la función por su nombre. En cambio, la función se llama por referencia. Cuando agregamos el detector de eventos, pasamos la función, y en ese punto es una variable, no una llamada a la función. Esta referencia es almacenada por el despachador de eventos y luego ejecutada dinámicamente cuando ocurre el evento (es un resumen de alto nivel real de cómo funciona el sistema de eventos, pero no tenemos tiempo para profundizar). Por lo tanto, la línea de código que en última instancia llama a la función que causa el error es una línea de código bastante genérica que utiliza el direccionamiento indirecto para realizar el trabajo y, por lo tanto, es mucho más difícil de atrapar para el compilador.

(En mi opinión, Adobe podría al menos registrar la addEventListener línea en tiempo de compilación, y vaya buscando la referencia de función por nombre. Si encuentra una coincidencia, podría verificar la firma de la función para un argumento de evento adecuado y producir errores en consecuencia. Todavía no se puede hacer de una manera infalible, pero puede ayudar a detectar estos errores antes de ejecutar el SWF..

Sin embargo, el punto principal es que este error en tiempo de ejecución tiene una contraparte en tiempo de compilación, pero que el error en tiempo de ejecución ocurre cuando se llama a la función por referencia y no directamente por nombre.


Paso 4: arreglando el agujero

La lluvia está llegando cuando llamamos a la función por referencia, y tenemos una discrepancia en el número de argumentos. Generalmente tenemos dos opciones: podemos modificar la llamada o modificar los argumentos de la función. En este ejemplo particular, no podemos modificar la llamada, ya que eso sucede dentro EventDispatcher, Código al que no tenemos acceso. Eso nos deja con modificar los argumentos..

Esto, de nuevo, tiene dos opciones. Primero, podemos simplemente agregar el argumento. Esto alinea el número de argumentos y de aquí en adelante, todo será copacético. No necesitamos usar el argumento, solo necesitamos tener la función? Catch? cuando se llama.

 función onClick (e: MouseEvent): void 

La segunda opción es, nuevamente, agregar el argumento (no hay forma de evitar eso, me temo). Sin embargo, si originalmente escribió la función como una función normal y no como un detector de eventos, y la está llamando desde otro lugar en su código sin argumentos, es posible que aprecie esta variación. Haga que el argumento sea opcional y que el valor predeterminado sea nulo:

 función onClick (e: MouseEvent = null): void 

Esto funcionará bien con el sistema de eventos: recibe un objeto de evento y puede atraparlo. También funciona bien con su código existente; Si no se envía ningún argumento, se utiliza el parámetro predeterminado y la función continúa..


Paso 5: devoluciones de llamada

Tenga en cuenta que este error no se limita a los escuchas de eventos, aunque probablemente sea el contexto más común donde lo experimentará. En última instancia, es el uso de funciones almacenadas en variables, a diferencia de las llamadas por su nombre, lo que conduce al error. Así es como funciona el sistema de eventos. Podemos volver a trabajar el ejemplo original para producir más o menos el mismo error, solo sin el clic:

 función sayMyName (name: String): void trace ("Hello," + name);  var funcRef: Function = sayMyName; funcRef ();

Nuevamente, superamos el error del compilador porque tenemos una capa de direccionamiento indirecto entre la definición de la función y la llamada a la función. Por lo tanto, obtenemos el error de tiempo de ejecución (esperado 1, obtuve 0).

Sin embargo, no siempre es este corte y seco. Si utiliza devoluciones de llamada en su código, puede ser presa del error 1063. Las devoluciones de llamada son similares a los escuchas de eventos, solo que no hay un mecanismo formal incorporado para implementarlas. Básicamente, son funciones que se pasan por referencia, que se almacenan (ya sea temporalmente oa largo plazo) por algún otro proceso, que luego llama a la función de devolución de llamada en el momento adecuado..

Los motores de interpolación suelen implementar estos. Algunos optan por un sistema más formal basado en eventos, pero TweenLite, por ejemplo, utiliza devoluciones de llamada para recibir notificaciones sobre el progreso de la interpolación. Esta línea:

 TweenLite.to (someClip, 1, onComplete: tweenFinished, onCompleteParams: [42, "answer"]);

? llamaría a una función llamada TweenFinished al final de la interpolación, pasando dos parámetros a la función. Esta técnica es, en última instancia, más flexible que los eventos, ya que no está limitado solo al objeto de evento único como parámetro. Pero sí se entrega a vulnerabilidades similares al error 1063 debido a la naturaleza de pasar funciones por referencia.


Eso es todo

Eso envuelve otro Consejo rápido de depuración. Gracias por leer, y espero que hayas aprendido algo en el camino.!