Snabbtips Så här debuggar du ett AS3-fel # 1009

En av de vanligaste frågorna jag ser på forum och få från kollegor är hur man debugger Error 1009, även känd som "Null Object Reference Error." Eller, som jag kallar det, "irriterande myggfelet från helvetet." Det väcker mycket, och tyvärr innehåller inte felet mycket information om källan till felet. I det här snabba tipset tar vi en titt på några steg du kan ta för att spåra denna mygga och squash det bra.


Introduktion

Denna del är den första uppföljningen till den mer generella? Fixing Bugs i AS3? handledning. Om du vill bättre förstå några av teknikerna i detta tips kanske du vill läsa det fullständigt först.


Steg 1: Förstå felet

Det är synd att Adobe inte (eller kan inte) ge mer information om roten till det här felet. Först och främst är det ganska obtrusivt formulerat (ungefär som alla sina fel, men det här är mer än de flesta):

TypeError: Error # 1009: Kan inte komma åt en egenskap eller metod för en null objektreferens

Låt oss försöka sätta detta i vardagliga termer. Fel 1009 innebär att du har försökt att göra något med en variabel som du antar har ett värde, men det gör det inte. Flash gillar inte det. Du skulle inte gilla det heller; Tänk dig att du hade ett glas som du antog var fullt av den läckra drycken du själv valde, men var verkligen tom. Du tar tag i glaset och förväntar dig en uppfriskande sug, men du känner dig i stället av den tappande vikten av ett tomt glas. Det är ditt eget personliga fel 1009.

I ActionScript, om du gör det här:

 Var s: String; trace (s.toUpperCase ());

Flash kommer bum hårt (en teknisk term för? Skapa ett fel?) När du kör koden. Variabeln s kan ha förklarats, men dess värde är null (vi satte aldrig värdet, precis deklarerade variabeln), så ringde toUpperCase Metoden på den är besvärlig.

För att vara tydlig, för s förklaras som en Sträng, de kompilator tar ingen fråga med koden: det finns en variabel som heter s, det är en Sträng, och toUpperCase är en giltig metod att ringa på Strängs. Felet vi får är a körning fel, vilket innebär att vi bara får det när vi kör SWF. Först när logiken utförs får vi nu se hur det visar sig.


Steg 2: Tillåt debugging

Precis som med eventuella kör-tid fel, ibland är det ganska lätt att berätta vad som händer utan extra information. Men andra gånger är det bra att minska detta ytterligare. Vid denna tid försöker du aktivera? Tillåt debugging.? När detta är aktiverat får du fel som också ger dig radnummer. Alternativt kan du kanske? Debug Movie? genom att trycka på Command-Shift-Return / Control-Shift-Enter.

För att göra det, se den allmänna felsökningstipsartikeln,? Fasta fel i AS3?

Ibland är det tillräckligt. Att veta den specifika raden kan vara all information du behöver. Om inte, graver vi lite djupare i nästa steg.

Vår kära redaktör, Michael James Williams, inkapslade punkten i det här steget i en limerick, som jag gärna presenterar för dig nu med hans vänliga tillstånd:

AS3 fel en-oh-oh-nio
Är aldrig ett mycket bra tecken.
Inget behov av oro,
Hit Ctrl-Shift-Return
Och det kommer att ange orsaken (väl, linjen).


Steg 3: Starta spårning

Om du har hittat den oupphörliga raden men fortfarande är osäker på vad som händer, plocka ut raden. Ta varje variabel i den linjen och spåra dem ut före felet.

Eftersom felet kommer när man får tillgång till en egenskap eller ringer en metod på en null-variabel, för att täcka dina baser bör du spåra några variabler och egenskaper som omedelbart följs av en punkt. Ta till exempel den här koden:

 myArray.push (someSprite.stage.align.toLowerCase ());

Visst är det en ganska konstruerad kod som jag inte kan tänka mig en praktisk användning för, men du borde identifiera fyra totalt möjligt null värden som nås med pricken:

  • myArray: vi ringer till tryck metod för denna variabel
  • someSprite: Vi har tillgång till skede fast egendom
  • skede: Vi har tillgång till justera fast egendom
  • justera: vi ringer till toLowerCase metod

Så din debugging-kod kan se ut så här:

 spår ("myArray:", myArray); spår ("someSprite:", someSprite); spår ("someSprite.stage:", someSprite.stage); spår ("someSprite.stage.align:", someSprite.stage.align);

Order är viktigt; om someSprite är null objektet, men du testar för someSprite.stage.align före testning för someSprite, du hamnar med mindre definitiva resultat.

Nu är det också sunt förnuft som spelar in i detta. I mitt exempel, om skede existerar då justera kommer med största säkerhet att ha ett värde; de Skede har alltid en justera inställning, även om det är standardvärdet.

Vanligtvis ser du något av följande:

 myArray: [? saker i matrisen? ] someSprite: [object Sprite] someSprite.stage: null Fel # 1009:? 

Vilket borde leda dig till att skede egendom är null, och nu kan du gå om att fixa den.


Steg 4: Hitta en lösning

Den enklaste lösningen är att pakka upp det motsatta uttalandet i en? Om? blockera, och kör bara blocket om den ifrågavarande variabeln inte är noll. Så, förutsatt att det i vårt tidigare exempel var det faktiskt skede det var null, vi kunde göra något så här:

 om (someSprite.stage) myArray.push (someSprite.stage.align.toLowerCase ()); 

Detta test - om (someSprite.stage) - kommer att återvända Sann om det finns ett värde (oavsett värde), och falsk om det är null. I allmänhet fungerar denna notation; du kan alltid använda om (someSprite.stage! = null) om du föredrar. siffras presenterar en något annorlunda situation. Om siffra har ett värde av 0, då har det tekniskt ett värde, men testning om (someNumberThatEqualsZero) kommer att utvärdera till falsk. För siffras du kan använda isNaN () funktion för att bestämma om ett giltigt numeriskt värde är lagrat i en given variabel.

I alla fall är den här tekniken ett enkelt sätt att skjuta upp felet. Om den variabel vi vill utföra en operation på inte är inställd, gör inte operationen. Om det inte finns någon god dryck i vårt glas, hämta inte glaset. Enkelt nog.

Men det här är bara möjligt om logiken är frivillig. Om logiken är nödvändig kan du kanske ge ett standardvärde till den ifrågasatta variabeln före felningsoperationen. Till exempel, om myArray har potential att vara null, men det är absolut nödvändigt att det inte är det vi kan göra här:

 om (! myArray) myArray = [];  myArray.push (someSprite.stage.align.toLowerCase ());

Detta kontrolleras först för att se om arrayen är null. Om det är, initiera det till en tom array (en tom array är ett giltigt värde. Det kan vara tomt, men det är en array och inte null) innan du kör den konstruerade koden. Om det inte är det null, Hoppa direkt till den konstruerade koden. I verkliga termer, om vårt glas är tomt fyller du det med en god dryck innan du tar upp den.

Dessutom, om myArray är en instansegenskap för den klass där den här koden körs, kan du ganska säkert försäkra ett giltigt värde genom att initialisera dina egenskaper när objektet initierar.

Vad händer om logiken krävs, men den ifrågavarande variabeln är inte så lätt under vår kontroll? Till exempel, om vår konstruerade kodkod krävs, men den tvivelaktiga variabeln är someSprite.stage? Vi kan inte bara ställa in skede fast egendom; som styrs internt till Display och är skrivskyddad för oss bara dödliga. Då kan du behöva bli häftig och läsa nästa steg.


Steg 5: Hantera a null skede

Det finns förmodligen ett oändligt antal scenarier där en viss variabel eller egenskap kan vara null. Självklart kan jag inte täcka dem alla i en snabb tips. Det finns en viss situation, men det växer upp igen och igen.

Låt oss säga att du skriver en kod som ser ut så här:

 public class QuickSprite utökar Sprite public function QuickSprite () stage.addEventListener (MouseEvent.MOUSE_MOVE, onMove);  privat funktion onMove (e: MouseEvent): void var färg: ColorTransform = new ColorTransform (); color.color = stage.mouseX / stage.stageWidth * 0xFFFFFF; this.transform.colorTransform = color; 

En annan konstruerad bit kod (som kan inducera anfall - anser sig varna), men i princip är tanken att du har en Sprite underklass och du ställer in det som klass för ett klipp på scenen, med hjälp av Flash IDE.

Du bestämmer dock att du vill arbeta med dessa QuickSprites programmatiskt. Så du försöker detta:

 var qs: QuickSprite = ny QuickSprite (); addChild (qs);

Och du får det förbannade felet 1009. Varför? Eftersom i QuickSprite konstruktör, du kommer åt skede egendom (ärvt från Display). När objektet skapas helt med kod, är det inte på scenen vid den punkten som den här koden körs, vilket betyder skede är null och du får felet. De QuickSprite läggs till nästa linje, men det är inte tillräckligt snart. Om förekomsten skapas genom att dra en symbol ut ur biblioteket och på scenen, så finns det lite magi på jobbet bakom kulisserna som ser till att förekomsten är på scenen (det vill säga skede egendom är inställt) under konstruktören.

Så här är vad du gör: du testar förekomsten av ett värde för skede. Beroende på resultatet kan du antingen köra uppställningskoden direkt eller konfigurera en annan händelseläge för när QuickSprite får läggas till scenen. Något som det här:

 offentlig funktion QuickSprite () if (stadium) init ();  annat this.addEventListener (Event.ADDED_TO_STAGE, init);  privatfunktion init (e: Event = null) this.removeEventListener (Event.ADDED_TO_STAGE, init); stage.addEventListener (MouseEvent.MOUSE_MOVE, onMove); 

Om vi ​​flyttar skede linje till en annan funktion, och bara ringa den funktionen när vi har ett stadium, då är vi inställda. Om skede finns från början, fortsätt och spring i det() direkt. Om inte, använder vi i det() som händelse lyssnare funktion för ADDED_TO_STAGE, vid vilken tidpunkt kommer vi att ha ett scenvärde och kan köra koden. Nu kan vi använda klassen för att antingen ansluta till IDE Sprite eller helt programmässigt.

Det fungerar också bra i dokumentklasser. När du kör en SWF i sig har dokumentklassen omedelbar tillgång till skede. Om du laddar den SWF-filen till en annan SWF, körs koden i dokumentklassens initialiseringsstack innan den inmatade SWF läggs till i teckenfönstret. En liknande skede-kontrollticket låter dig arbeta med SWF som både en fristående bit och som en SWF laddad i en innehållande SWF.


Det är allt

Tack för att du läste den här snabba tipsen! Jag hoppas att du är upplyst lite om hur fel 1009 inträffar, och hur du kan felsöka det. Håll dig klar för mer snabba tips om andra vanliga fel.