Snelle tip Hoe een AS3-fout # 1063 te debuggen

Het is tijd voor een nieuwe Quick Quick-foutopsporing. We blijven onze aandacht richten op specifieke (en veel voorkomende) fouten die minder ervaren ActionScript-gebruikers blokkeren. In dit geval behandelen we Fout # 1063, de fout voor het tellen van niet-overeenkomende argumenten.


Stap 1: Slecht zijn

Laten we eerst een situatie creëren waarin de fout optreedt. Open een nieuw Flash-document (ervan uitgaande dat u meegaat met Flash Pro CS3 +, anders kan dit voorbeeld eenvoudig worden aangepast aan een Flex-project). Open de Scripteditor en voer de volgende code in:

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

Je kunt het probleem waarschijnlijk al opmerken; Als je enige tijd hebt besteed aan het schrijven van ActionScript 3, merk je dat je event handlers schrijft. Zo niet, voel je dan niet slecht - we zullen het allemaal te zijner tijd bespreken.

Als u het Flash-bestand als zodanig uitvoert en vervolgens op het werkgebied klikt, wordt het volgende runtimefoutbericht weergegeven:

 ArgumentError: Fout # 1063: aantal argumenten komt niet overeen op Untitled_fla :: MainTimeline / onClick (). Verwachte 0, heb er 1.

En we komen nooit op de traceerinstructie moeten zijn uitgevoerd na klikken.


Stap 2: Breaking It Down

Dus wat is er aan de hand? In dit geval is de woordenstroom van Adobe voor de fout eigenlijk niet zo slecht, en als u gewend bent geraakt aan het parseren van een runtimefoutbericht, is de betekenis ervan vrij duidelijk. Maar niet iedereen is zo slim als jij, dus hier is de verdeling voor iedereen.

ArgumentError -- Dit is enigszins inconsequente informatie, maar het geeft het specifieke weer Fout klasse die werd gegooid. We hebben iets dat niet zo algemeen is als een simpel Fout, en we hebben een specifieke categorisatie van fouten ingevoerd die geassocieerd is met argumenten (naar functies en methoden).

Fout # 1063 -- Hier geven we alleen het formele foutnummer, zoals alle goede uitvoeringsfouten. U kunt deze code gebruiken om deze gemakkelijker te vinden in de runtime-foutdocumentatie van Adobe.

Aantal niet-overeenkomende argumenten? -- In meer proletarische termen was er het verkeerde aantal argumenten verzonden naar een functie. Welke functie? Haar?

? op Untitled_fla :: MainTimeline / onClick (). -- Dit identificeert eenvoudig de functie die het verkeerde aantal argumenten heeft ontvangen.

Verwachte 0, heb er 1. -- We krijgen een beetje extra informatie in deze foutbeschrijving. Dit detailleert de telling komt niet overeen. Deze zin zal veranderen afhankelijk van de aard van de specifieke fout, maar in ons geval zegt hij dat de functie zonder enige argumenten in de handtekening is geschreven, maar er is toch een enkel argument naar toe gestuurd.

Flash vindt zijn eenden op een rij leuk. Dus, het merkt deze discrepantie op en besluit er een te gooien woedeaanval fout, omdat het liever is dat u (de ontwikkelaar) hebt uitgezocht wat er mis ging dan dat u eenvoudigweg het probleem negeerde. Dit is goed, want als de niet-overeenkomende telling de andere kant op zou gaan (verwachte 1, kreeg 0), dan zouden we vastzitten zonder een argument voor een vereiste parameter, en de functie zou doen. Dog weet wat.


Stap 3: De oorzaak van het probleem

De aard van de fout zou op dit punt duidelijk moeten zijn, maar u vraagt ​​zich misschien nog steeds af waarom deze zich heeft voorgedaan. Waar komt dat overtollige argument vandaan?

Het argument is niet echt overbodig. Het wordt eigenlijk verwacht, omdat we onze functie hebben gekoppeld aan een gebeurtenislistener. Het gebeurtenissensysteem in Flash heeft het idee van een gebeurtenisobject die aspecten van de gebeurtenis die zich heeft voorgedaan samenvat. Dit object wordt doorgegeven aan de luisteraarfunctie als het enige argument. Zodat we verwacht 0 omdat we onze functie zonder parameters hebben geschreven, maar wij heb 1 omdat de gebeurtenisverdeler een gebeurtenisobject heeft verzonden.

Nu vraag je je misschien af ​​waarom de compiler deze fout niet heeft opgemerkt. Het is waar: als je dit hebt geschreven:

 function sayClick (): void trace ("click.");  zegKlik (42);

Dan zal de SWF niet eens compileren, omdat je deze fout krijgt:

 1137: onjuist aantal argumenten. Verwacht niet meer dan 0.

Het verschil is dat we in het laatste voorbeeld een code hebben die de functie met het verkeerde aantal argumenten aanroept. Dat wil zeggen, we hebben de regel geschreven die de functie onjuist noemt. De compiler kan kijken naar de regel die de functie definieert, en de regel die de functie oproept, en deze vergelijken voor verschillen en het alarm laten klinken wanneer ze zich voordoen.


Afbeelding door Alan / Falcon

In het oorspronkelijke voorbeeld is er echter geen regel code genoteerd die de functie letterlijk op naam noemt. In plaats daarvan wordt de functie door verwijzing genoemd. Wanneer we de gebeurtenislistener toevoegen, geven we de functie door en op dat moment is het een variabele, geen functieaanroep. Deze referentie wordt opgeslagen door de gebeurtenisverdeler en vervolgens dynamisch uitgevoerd wanneer de gebeurtenis plaatsvindt (dat is een echt overzicht op hoog niveau van hoe het gebeurtenissysteem werkt, maar we hebben geen tijd om dieper in te gaan). De coderegel die uiteindelijk de foutveroorzakende functie oproept, is dus een vrij algemene coderegel die indirect gebruik maakt om de klus te klaren, en daarom is het voor de compiler iets veel moeilijker om te vangen.

(Naar mijn mening kon Adobe het register op zijn minst registreren addEventListener regel bij het compileren, en ga op zoek naar de functie referentie op naam. Als het een overeenkomst vindt, kan het de handtekening van de functie controleren op een passend gebeurtenisargument en dienovereenkomstig fouten produceren. Het kon nog steeds niet op een waterdichte manier gedaan worden, maar het zou een lange weg kunnen banen om deze fouten te vangen voordat de SWF daadwerkelijk wordt uitgevoerd.

Het belangrijkste punt is echter dat deze runtime-fout een compilatietijd-tegenhanger heeft, maar dat de runtimefout optreedt wanneer de functie wordt opgeroepen door verwijzing en niet direct op naam.


Stap 4: Het gat repareren

De regen komt binnen wanneer we de functie door verwijzing noemen en een discrepantie hebben in het aantal argumenten. We hebben over het algemeen twee opties: we kunnen de oproep aanpassen of de argumenten van de functie wijzigen. In dit specifieke voorbeeld kunnen we de oproep niet wijzigen, omdat dat binnen gebeurt EventDispatcher, code waartoe we geen toegang hebben. Dat laat ons met het wijzigen van de argumenten.

Dit heeft wederom twee opties. Ten eerste kunnen we eenvoudigweg het argument toevoegen. Dit rangschikt het aantal argumenten en vanaf nu is alles copacetisch. We hoeven het argument niet te gebruiken, we moeten gewoon de functie hebben? Vangen? het wanneer het wordt genoemd.

 function onClick (e: MouseEvent): void 

De tweede optie is om, nogmaals, het argument toe te voegen (geen weg er omheen, vrees ik). Als je de functie echter oorspronkelijk hebt geschreven als een reguliere functie en niet als een gebeurtenislistener, en deze zonder argumenten ergens anders in je code oproept, kun je deze variatie waarderen. Maak het argument optioneel en stel het standaard in nul:

 function onClick (e: MouseEvent = null): void 

Dit zal goed werken met het evenementensysteem: het krijgt een gebeurtenisobject toegestuurd en kan het vangen. Het werkt ook goed met uw bestaande code; als er geen argument wordt verzonden, wordt de parameterinstelling gebruikt en gaat de functie verder.


Stap 5: callbacks

Merk op dat deze fout niet beperkt is tot gebeurtenislisteners, hoewel dat waarschijnlijk de meest voorkomende context is waar je het zult ervaren. Uiteindelijk is het het gebruik van functies opgeslagen in variabelen, in tegenstelling tot bij naam genoemd, die tot de fout leiden. Dit is hoe het gebeurtenissysteem werkt. We kunnen het oorspronkelijke voorbeeld herwerken om min of meer dezelfde fout te produceren, alleen zonder de klik:

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

Nogmaals, we passeren de compileerfout omdat we een laag van indirectie hebben tussen de functiedefinitie en de functieaanroep. Zo krijgen we de run-time error (verwachte 1, kreeg 0).

Het is echter niet altijd zo droog en droog. Als u callbacks gebruikt in uw code, kunt u ten prooi vallen aan fout 1063. Callbacks zijn vergelijkbaar met gebeurtenislisteners, maar er is geen formeel, ingebouwd mechanisme om deze toe te passen. Het zijn in feite gewoon functies die u doorgeeft door te verwijzen, die worden opgeslagen (tijdelijk of op lange termijn) door een ander proces, dat vervolgens de callback-functie op het juiste moment oproept.

Tweening-engines implementeren deze meestal. Sommigen gaan voor een meer formeel door gebeurtenissen gestuurd systeem, maar TweenLite maakt bijvoorbeeld gebruik van callbacks voor het ontvangen van meldingen over de tween-voortgang. Deze lijn:

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

? zou een functie genaamd noemen tweenFinished aan het einde van de tween, twee parameters doorgeven aan de functie. Deze techniek is uiteindelijk flexibeler dan gebeurtenissen, omdat je niet beperkt bent tot alleen het enkelvoudige gebeurtenisobject als parameter. Maar het levert zichzelf op voor dezelfde kwetsbaarheden als voor fout 1063 vanwege de aard van passerende functies door verwijzing.


Dat is alles

Dat omhult een andere snelle foutopsporing. Bedankt voor het lezen en ik hoop dat je onderweg iets hebt geleerd!