Det er på tide for en annen feilsøking. Vi vil fortsette vårt fokus på spesifikke (og vanlige) feil som har en tendens til å stymie mindre erfarne ActionScripters. I dette tilfellet vil vi dekke feil # 1063, argumentet teller feilfeil.
La oss først lage en situasjon der feilen oppstår. Åpne et nytt Flash-dokument (forutsatt at du følger med Flash Pro CS3 +, ellers er denne prøven enkelt tilpasset et Flex-prosjekt). Åpne Skripteditoren og skriv inn følgende kode:
importer flash.events.MouseEvent; funksjon onClick (): void trace ("click."); stage.addEventListener (MouseEvent.CLICK, onClick);
Du kan sannsynligvis se problemet allerede; Hvis du har brukt litt tid på å skrive ActionScript 3, har du funnet deg selv å skrive hendelsesbehandlere. Hvis ikke, ikke føl deg dårlig - vi vil gå over alt med tiden.
Hvis du kjører Flash-filen som det er, og deretter klikker du på scenen, vil du produsere følgende feilmelding om kjøretid:
ArgumentError: Feil # 1063: Argument count mismatch på Untitled_fla :: MainTimeline / onClick (). Forventet 0, fikk 1.
Og vi kommer aldri til sporoppgaven at bør har kjørt etter å ha klikket.
Så hva skjer? I dette tilfellet er Adobes verbiage for feilen egentlig ikke så ille, og hvis du har blitt vant til å analysere en feilmeldingsfeil, kan dens betydning være ganske tydelig. Men ikke alle er like smarte som deg, så her er sammenbrudd for alle andre.
ArgumentError -- Dette er noe ubetydelig informasjon, men det viser det spesifikke Feil
klassen som ble kastet. Vi har noe som ikke er så generelt som enkelt Feil
, og vi har angitt en bestemt kategorisering av feil knyttet til argumenter (til funksjoner og metoder).
Feil # 1063 -- Her gir vi bare det formelle feilnummeret, som alle gode run-time-feil. Du kan bruke denne koden til å enklere finne den i Adobes feilsøkingsdokumentasjon.
Argumenttall feil samsvar? -- I flere proletariske termer var det feil antall argumenter sendt til en funksjon. Hvilken funksjon? Det er?
? på Untitled_fla :: MainTimeline / onClick (). -- Dette identifiserer bare funksjonen som mottok feil antall argumenter.
Forventet 0, fikk 1. -- Vi får litt ekstra informasjon i denne feilbeskrivelsen. Dette angir antall feilmatch. Denne setningen vil endres i henhold til arten av den spesifikke feilen, men i vårt tilfelle sier det at funksjonen ble skrevet uten argumenter i signaturen, men et enkelt argument ble sendt til det uansett.
Flash liker sine ender på rad. Så det merker denne uoverensstemmelsen og bestemmer seg for å kaste en raserianfall feil, fordi det ville heller du (utvikleren) funnet ut hva som gikk galt enn det du bare ignorert problemet. Dette er bra, fordi hvis tellefeilpasningen gikk den andre veien (forventet 1, fikk 0), da ville vi bli sittende fast uten argument for en nødvendig parameter, og funksjonen ville gjøre hunden vet hva.
Feilens art burde være tydelig på dette punktet, men du kan fortsatt lure på hvorfor det skjedde i det hele tatt. Hvor kom det overflødige argumentet fra?
Argumentet er ikke akkurat overflødig. Det er faktisk forventet, siden vi har koblet opp vår funksjon til å være en hendelselytter. Hendelsessystemet i Flash har begrepet an hendelsesobjekt som encapsulates aspekter av hendelsen som skjedde. Dette objektet blir sendt til lytterfunksjonen som det eneste argumentet. Så, vi forventet 0 fordi vi skrev vår funksjon uten noen parametere, men vi fikk 1 fordi hendelsesforsendelsen sendes langs et hendelseobjekt.
Nå kan du kanskje lure på hvorfor kompilatoren ikke fant denne feilen. Det er sant: Hvis du skrev dette:
funksjon sayClick (): void trace ("click."); sayClick (42);
Da vil SWF ikke engang kompilere, fordi du får denne feilen:
1137: Feil antall argumenter. Forventet ikke mer enn 0.
Forskjellen er at i sistnevnte eksempel har vi faktisk kode som kaller funksjonen med feil antall argumenter. Det er, vi skrev linjen ned som kaller funksjonen feil. Kompilatoren kan se på linjen som definerer funksjonen, og linjen som kaller funksjonen, og sammenligner dem for uoverensstemmelser, og larm alarmen når de oppstår.
Imidlertid er det i det opprinnelige eksemplet ingen kodekode skrevet ned som bokstavelig talt kalles funksjonen ved navn. I stedet blir funksjonen kalt ved referanse. Når vi legger til hendelseslytteren, passerer vi inn i funksjonen, og på det tidspunktet er det en variabel, ikke en funksjonsanrop. Denne referansen blir lagret av hendelsesleverandøren, og deretter utført dynamisk når hendelsen oppstår (det er en ekte høyt overblikk over hvordan hendelsessystemet fungerer, men vi har ikke tid til å gå dypere). Så koden av koden som i siste instans kalles feilfeilfunksjonen, er en ganske generisk linje med kode som bruker indireksjon for å få jobben gjort, og derfor noe mye vanskeligere for kompilatoren å fange.
(Etter min mening kunne Adobe i det minste registrere addEventListener
linje på kompileringstid, og se etter funksjonsreferansen etter navn. Hvis den finner en kamp, kan den sjekke funksjons signaturen for et riktig hendelsesargument, og produsere feil tilsvarende. Det kan fortsatt ikke gjøres på en idiotsikker måte, men det kan gå langt for å fange disse feilene før du faktisk kjører SWF.
Hovedpoenget er imidlertid at denne run-time-feilen har en kompileringstidsmotpart, men at run-time-feilen oppstår når funksjonen kalles ved referanse og ikke direkte ved navn.
Regnet kommer inn når vi kaller funksjonen ved referanse og har en avvik i antall argumenter. Vi har vanligvis to alternativer: Vi kan endre samtalen eller endre funksjonens argumenter. I dette spesielle eksempelet kan vi ikke endre anropet, som det skjer inni EventDispatcher
, kode som vi ikke har tilgang til. Det etterlater oss med å endre argumenter.
Dette har igjen to alternativer. Først kan vi bare legge til argumentet. Dette linjer opp antall argumenter og herfra ut, vil alt være copasetisk. Vi trenger ikke å bruke argumentet, vi trenger bare å ha funksjonen? det når det kalles.
funksjon onClick (e: MouseEvent): void
Det andre alternativet er å, igjen, legge til argumentet (ingen vei rundt det, jeg er redd). Men hvis du opprinnelig skrev funksjonen som en vanlig funksjon og ikke en hendelseslytter, og kaller den fra andre steder i koden din uten argumenter, kan du sette pris på denne varianten. Gjør argumentet valgfritt, og standardiser det til null
:
funksjon onClick (e: MouseEvent = null): void
Dette vil fungere godt med arrangementssystemet: det blir sendt et hendelseobjekt og kan fange det. Det fungerer også bra med din eksisterende kode; Hvis det ikke sendes noe argument, brukes parameterens standard og funksjonen fortsetter.
Vær oppmerksom på at denne feilen ikke er begrenset til hendelseslyttere, men det er trolig den vanligste konteksten der du opplever det. Til syvende og sist er det bruk av funksjoner lagret i variabler, i motsetning til kalt etter navn, som fører til feilen. Slik fungerer arrangementet. Vi kan omarbeide det opprinnelige eksemplet for å produsere mer eller mindre den samme feilen, bare uten å klikke:
funksjon sayMyName (navn: String): void trace ("Hei," + navn); var funcRef: Funksjon = sayMyName; funcRef ();
Igjen, vi kommer forbi kompilatorfeilen fordi vi har et lag av indirection mellom funkjonsdefinisjonen og funksjonssamtalen. Dermed får vi run-time-feilen (forventet 1, fikk 0).
Det er ikke alltid dette kuttet og tørt, skjønt. Hvis du bruker tilbakekallinger i koden din, kan du bli byttet til feil 1063. Tilbakeringinger er slags som hendelseslyttere, bare det er ingen formell, innebygd mekanisme for å implementere dem. De er i utgangspunktet bare funksjoner du passerer rundt ved referanse, som lagres (enten midlertidig eller langsiktig) av en annen prosess, som deretter kaller tilbakeringingsfunksjonen på riktig tidspunkt.
Tweening-motorer implementerer vanligvis disse. Noen går til et mer formelt hendelse-drevet system, men TweenLite bruker for eksempel tilbakekallinger for å motta varsler om tween-fremgangen. Denne linjen:
TweenLite.to (someClip, 1, onComplete: tweenFinished, onCompleteParams: [42, "svar"]);
? ville ringe en funksjon som heter tweenFinished
på slutten av tween, passerer to parametre til funksjonen. Denne teknikken er i siste instans mer fleksibel enn hendelser, da du ikke er begrenset til bare det enkelte hendelsesobjekt som en parameter. Men det gir seg til liknende sårbarheter for feil 1063 på grunn av naturen til å overføre funksjoner ved referanse.
Det bryter opp en annen Debugging Quick Tip. Takk for at du leser, og jeg håper du lærte noe underveis!