Et av de vanligste spørsmålene jeg ser på fora og få fra kollegaer, er hvordan du feilsøker Feil 1009, også kjent som "Null Object Reference Error." Eller, som jeg kaller det, den? Irriterende Myggfeilen fra helvete.? Det avleder mye, og dessverre inneholder feilen ikke mye informasjon om kilden til feilen. I dette raske tipset tar vi en titt på noen skritt du kan ta for å spore opp denne mygggen og squash den godt.
Dette stykket er den første oppfølgeren til den mer generelle? Fixing Bugs i AS3? opplæringen. Hvis du ønsker å bedre forstå noen av teknikkene i dette tipset, kan du ønske å lese det i sin helhet først.
Det er synd at Adobe ikke (eller ikke) kan gi mer informasjon om roten til denne feilen. Først og fremst er det ganske tøft formulert (som alle sine feil, men dette er mer enn de fleste):
TypeError: Feil # 1009: Kan ikke få tilgang til en egenskap eller metode for null-objektreferanse
La oss prøve å sette dette i hverdagen. Feil 1009 betyr at du har forsøkt å gjøre noe med en variabel som du antar, har en verdi, men egentlig ikke. Flash liker ikke det. Du vil ikke like det heller; forestill deg at du hadde et glass som du antok var fullt av den velsmakende drikkevaren du ønsket, men det var virkelig tomt. Du tar glasset og forventer en forfriskende snu, men i stedet føler du den skuffende vekten av et tomt glass. Det er din egen personlige feil 1009.
I ActionScript, hvis du gjør dette:
var s: streng; spor (s.toUpperCase ());
Flash vil bum hardt (et teknisk begrep for? Produsere en feil?) Når du kjører koden. Variabelen s
kan ha blitt erklært, men verdien er null
(vi har aldri satt verdien, nettopp erklært variabelen), så kaller toUpperCase
Metoden på den er plagsom.
Å være klar, fordi s
er erklært som en string
, de kompilatoren tar ingen problem med koden: det heter en variabel s
, det er en string
, og toUpperCase
er en gyldig metode for å ringe på string
s. Feilen vi får er en run-time feil, noe som betyr at vi bare får det når vi kjører SWF. Først når logikken utføres, får vi nå se hvordan dette viser seg.
Som med enhver run-time-feil, noen ganger er det ganske enkelt å fortelle hva som skjer uten ekstra informasjon. Men andre ganger er det nyttig å begrense dette videre. På dette tidspunktet kan du prøve å slå på? Tillat feilsøking.? Når dette er aktivert, får du feil som også gir deg linjenumre. Alternativt kan du kanskje? Debug Movie? ved å trykke på Command-Shift-Return / Control-Shift-Enter.
For å gjøre det, se den generelle debugging tips artikkelen,? Feste feil i AS3?
Noen ganger er dette nok. Å vite den spesifikke linjen kan være all den informasjonen du trenger. Hvis ikke, graver vi litt dypere i neste trinn.
Vår kjære redaktør, Michael James Williams, innkapslet poenget med dette trinnet i en limerick, som jeg gjerne presenterer for deg nå med sin hyggelige tillatelse:
AS3 feil en-oh-oh-ni
Er aldri et veldig godt tegn.
Ingen bekymring,
Trykk Ctrl-Shift-Return
Og det vil finne årsaken (vel, linjen).
Hvis du har funnet den ulovlige linjen, men fortsatt er usikker på hva som skjer, plukk fra linjen. Ta hver variabel i den linjen og spor dem ut i forkant av feilen.
Fordi feilen kommer når du åpner en egenskap eller kaller en metode på null-variabel, bør du spore noen variabler og egenskaper som umiddelbart etterfølges av en prikk for å dekke basisene dine. Ta for eksempel denne linjen med kode:
myArray.push (someSprite.stage.align.toLowerCase ());
Admittedly, det er en ganske konstruert kode som jeg ikke kan forestille meg en praktisk bruk for, men du burde identifisere fire totalt mulig null
verdier som nås med prikken:
myArray
: vi ringer til trykk
metode på denne variabelensomeSprite
: Vi har tilgang til scene
eiendomscene
: Vi har tilgang til rette inn
eiendomrette inn
: vi ringer til toLowerCase
metodeSå feilsøkingskoden din kan se slik ut:
spor ("myArray:", myArray); spor ("noenSprite:", noenSprite); spor ("noenSprite.stage:", someSprite.stage); spor ("someSprite.stage.align:", someSprite.stage.align);
Bestillingen er viktig; hvis someSprite
er null objektet, men du tester for someSprite.stage.align
før testing for someSprite
, du ender med mindre endelige resultater.
Nå spiller også sunn fornuft også inn i dette. I mitt eksempel, hvis scene
eksisterer da rette inn
vil helt sikkert ha en verdi; de Scene
har alltid en rette inn
innstilling, selv om det er standardverdien.
Vanligvis ser du noe som følger:
myArray: [? ting i matrisen? ] someSprite: [object Sprite] someSprite.stage: null Feil # 1009:?
Hvilket burde clue deg i at scene
eiendommen er null
, og nå kan du gå om å fikse det.
Den enkleste løsningen er å pakke opp den motsatte setningen i en? Hvis? blokkere, og bare kjør blokken hvis den aktuelle variabelen ikke er null. Så, forutsatt at det i vårt tidligere eksempel var det faktisk scene
det var null
, vi kunne gjøre noe slikt:
hvis (noenSprite.stage) myArray.push (someSprite.stage.align.toLowerCase ());
Denne testen - hvis (noenSprite.stage)
- vil returnere ekte
hvis det er en verdi (uavhengig av verdien), og falsk
hvis det er null
. Generelt fungerer denne notasjonen; du kan alltid bruke hvis (noenSprite.stage! = null)
hvis du foretrekker. Nummer
s presenterer en litt annen situasjon, skjønt. Hvis Nummer
har en verdi på 0
, så teknisk har det en verdi, men testing hvis (noenNumberThatEqualsZero)
vil evaluere til falsk
. Til Nummer
s du kan bruke isNaN ()
funksjon for å bestemme om en gyldig numerisk verdi er lagret i en gitt variabel.
I alle fall er denne teknikken en enkel måte å skjule feilen på. Hvis variabelen vi vil utføre en operasjon på, ikke er angitt, må du ikke gjøre operasjonen. Hvis det ikke er velsmakende drikke i glasset, må du ikke plukke opp glasset. Enkel nok.
Men denne tilnærmingen er bare mulig hvis logikken er valgfri. Hvis logikken er nødvendig, kan du kanskje gi en standardverdi til den tvilsomme variabelen før feiloperasjonen. For eksempel, hvis myArray
har potensial til å være null
, men det er viktig at det ikke er det, vi kan gjøre dette:
hvis (! myArray) myArray = []; myArray.push (someSprite.stage.align.toLowerCase ());
Dette kontrollerer først for å se om arrayet er null
. Hvis det er, initialiser det til en tom rekkefølge (et tomt array er en gyldig verdi. Det kan være tomt, men det er en matrise, og ikke null
) før du kjører den utprøvde koden. Hvis det ikke er det null
, hoppe rett til den utprøvde koden. I virkeligheten, hvis glasset vårt er tomt, fyll det med en velsmakende drikke før du tar den opp.
I tillegg, hvis myArray
er en forekomst av klassen der denne linjen med kode kjører, kan du ganske sikkert sikre en gyldig verdi ved å initialisere egenskapene når objektet initialiserer.
Hva om logikken er nødvendig, men den aktuelle variabelen er ikke så lett under vår kontroll? For eksempel, hva om vår konstruerte kodekode er nødvendig, men den tvilsomme variabelen er someSprite.stage
? Vi kan ikke bare sette scene
eiendom; det styres internt til Displayobject
og er skrivebeskyttet for oss bare dødelige. Da må du kanskje bli slank og lese neste trinn.
null
sceneDet er sannsynligvis et uendelig antall scenarier hvor en gitt variabel eller egenskap kan være null
. Tydeligvis kan jeg ikke dekke dem alle i en rask tips. Det er en spesiell situasjon, men det kaster opp igjen og igjen.
La oss si at du skriver noen kode som ser slik ut:
offentlig klasse QuickSprite utvider Sprite offentlig funksjon QuickSprite () stage.addEventListener (MouseEvent.MOUSE_MOVE, onMove); privat funksjon onMove (e: MouseEvent): void var farge: ColorTransform = new ColorTransform (); color.color = stage.mouseX / stage.stageWidth * 0xFFFFFF; this.transform.colorTransform = color;
En annen utprøvd bit av kode (som kan forårsake anfall - vurdere deg selv advart), men i utgangspunktet er ideen at du har en Sprite
underklasse og du setter dette som klassen for et klipp på scenen, ved hjelp av Flash IDE.
Men du bestemmer deg for at du vil jobbe med disse QuickSprite
s programmatisk. Så du prøver dette:
var qs: QuickSprite = ny QuickSprite (); addChild (qs);
Og du får den forbannede feilen 1009. Hvorfor? Fordi i QuickSprite
Konstruktør, du får tilgang til scene
eiendom (arvet fra Displayobject
). Når objektet er opprettet helt med kode, er det ikke på scenen på det punktet at den aktuelle koden løper, noe som betyr scene
er null
og du får feilen. De QuickSprite
blir lagt til neste linje, men det er ikke så snart som mulig. Hvis forekomsten er opprettet ved å dra et symbol ut av biblioteket og på scenen, så er det litt magi på jobb bak kulissene som sikrer at forekomsten er på scenen (det vil si at scene
eiendommen er satt) under konstruktøren.
Så her er hva du gjør: du tester for eksistensen av en verdi for scene
. Avhengig av resultatet kan du enten kjøre oppsettkoden med en gang, eller sette opp en annen hendelselytter for når QuickSprite
blir lagt til scenen. Noe sånt som dette:
offentlig funksjon QuickSprite () hvis (stadium) init (); annet this.addEventListener (Event.ADDED_TO_STAGE, init); privatfunksjon init (e: Event = null) this.removeEventListener (Event.ADDED_TO_STAGE, init); stage.addEventListener (MouseEvent.MOUSE_MOVE, onMove);
Hvis vi flytter scene
linje til en annen funksjon, og bare ring den funksjonen når vi har et stadium, så er vi satt. Hvis scene
eksisterer fra starten, gå videre og løp i det()
med en gang. Hvis ikke, bruker vi i det()
som en hendelseslytterfunksjon for ADDED_TO_STAGE
, på hvilket tidspunkt vil vi ha en sceneværdi og kan kjøre koden. Nå kan vi bruke klassen for enten å koble til IDE Sprite eller helt programmatisk.
Dette fungerer også bra i dokumentklasser. Når du kjører en SWF av seg selv, har dokumentklassen umiddelbar tilgang til scene
. Hvis du laster den SWF-en til en annen SWF, blir koden i dokumentklassens initialiseringsstabel utført før den lastede SWF er lagt til i displayet. En lik scene
-kontrolltrick vil tillate deg å jobbe med SWF som både et frittstående stykke og som en SWF lastet inn i en inneholdende SWF.
Takk for at du leser denne raske tipsen! Jeg håper du er opplyst litt om hvordan Feil 1009 oppstår, og hvordan du kan feilsøke det. Hold deg oppdatert for mer raske tips om andre vanlige feil.