Een van de meer algemene vragen die ik op forums zie en krijg van collega's, is het debuggen van Error 1009, ook wel bekend als de? Null Object Reference Error.? Of, zoals ik het noem, de? Annoying Mosquito Error From Hell.? Het levert veel op, en helaas bevat de fout zelf niet veel informatie over de oorzaak van de fout. In deze snelle tip zullen we enkele stappen bekijken die u kunt nemen om deze mug op te sporen en goed te squashen.
Dit stuk is de eerste follow-up van de meer algemene? Fixing Bugs in AS3? tutorial. Als je een aantal van de technieken in deze tip beter wilt begrijpen, wil je dat misschien eerst volledig lezen.
Het is jammer dat Adobe niet (meer) informatie geeft over de oorzaak van deze fout. Allereerst is het nogal obtusely verwoord (net als al hun fouten, maar dit meer dan de meeste):
TypeError: Fout # 1009: Geen toegang tot een eigenschap of methode van een null-objectreferentie
Laten we dit in alledaagse termen proberen. Fout 1009 betekent dat u hebt geprobeerd iets te doen met een variabele waarvan u aanneemt dat deze een waarde heeft, maar dat is echt niet zo. Flash vindt dat niet leuk. Je zou het ook niet leuk vinden; Stel je voor dat je een glas had waarvan je aannam dat het vol zat met de smakelijke drank naar keuze, maar echt leeg was. Je pakt het glas, verwacht een verfrissende slok, maar je voelt in plaats daarvan het teleurstellende gewicht van een leeg glas. Dat is je eigen persoonlijke Fout 1009.
In ActionScript, als u dit doet:
var s: String; trace (s.toUpperCase ());
Flash zal hard schieten (een technische term voor? Produceer een fout?) Wanneer u de code uitvoert. De variabele s
mogelijk verklaard, maar de waarde is nul
(we hebben nooit de waarde ingesteld, alleen de variabele verklaard), dus de toUpperCase
methode erop is lastig.
Voor de duidelijkheid, omdat s
wordt verklaard als een Draad
, de compiler geen probleem met de code: er is een variabele genaamd s
, het is een Draad
, en toUpperCase
is een geldige methode om een beroep op te doen Draad
s. De fout die we krijgen is a run-time fout, wat betekent dat we het alleen krijgen als we de SWF uitvoeren. Pas als de logica wordt uitgevoerd, kunnen we nu zien hoe dit uitpakt.
Zoals met elke runtime-fout, is het soms vrij eenvoudig om te vertellen wat er gebeurt zonder extra informatie. Maar andere keren is het handig om dit verder te verfijnen. Probeer het nu in te schakelen? Foutopsporing toestaan? Wanneer dit is ingeschakeld, krijgt u fouten die u ook regelnummers geven. Als alternatief kun je het ook doen? Foutopsporing film? door op Command-Shift-Return / Control-Shift-Enter te drukken.
Zie hiervoor het algemene artikel over foutopsporingstips,? Bugs repareren in AS3?
Soms is dit genoeg. Het kennen van de specifieke regel is mogelijk alle informatie die u nodig hebt. Zo niet, dan graven we een beetje dieper in de volgende stap.
Onze lieve redacteur, Michael James Williams, vatte het punt van deze stap samen in een limerick, die ik u nu graag met zijn vriendelijke toestemming wil presenteren:
AS3-fout één-oh-oh-nine
Is nooit een heel goed teken.
Geen reden tot zorg,
Druk op Ctrl-Shift-Return
En het zal de oorzaak lokaliseren (nou ja, de regel).
Als u de overtredende regel hebt gevonden maar nog steeds niet zeker weet wat er aan de hand is, kunt u de regel uit elkaar halen. Neem elke variabele in die regel en traceer ze vóór de fout.
Omdat de fout optreedt bij het openen van een eigenschap of bij het aanroepen van een methode op een nulvariabele, moet u alle variabelen en eigenschappen volgen die onmiddellijk worden gevolgd door een punt. Neem bijvoorbeeld deze regel code:
myArray.push (someSprite.stage.align.toLowerCase ());
Toegegeven, dat is een tamelijk geforceerd stukje code dat ik me praktisch niet kan voorstellen, maar dat zou je moeten identificeren vier totaal mogelijk nul
waarden die worden benaderd met de punt:
myArray
: we noemen het Duwen
methode voor deze variabelesomeSprite
: we hebben toegang tot de stadium
eigendomstadium
: we hebben toegang tot de richten
eigendomrichten
: we noemen het toLowerCase
methodeUw foutopsporingscode ziet er dus als volgt uit:
trace ("myArray:", myArray); trace ("someSprite:", someSprite); trace ("someSprite.stage:", someSprite.stage); trace ("someSprite.stage.align:", someSprite.stage.align);
Bestelling is belangrijk; als someSprite
is het nul object, maar je test voor someSprite.stage.align
vóór het testen voor someSprite
, je krijgt uiteindelijk minder definitieve resultaten.
Nu speelt het gezond verstand hier ook op in. In mijn voorbeeld, als stadium
bestaat dan richten
zal zeker een waarde hebben; de Stadium
heeft altijd een richten
instelling, zelfs als dit de standaardwaarde is.
Meestal ziet u iets als het volgende:
myArray: [? dingen in de array? ] someSprite: [object Sprite] someSprite.stage: null Fout # 1009:?
Wat u moet weten dat het stadium
eigendom is nul
, en nu kun je het oplossen.
De eenvoudigste oplossing is om de aanstootgevende verklaring af te ronden in een? Als? blokkeren en voer het blok alleen uit als de betreffende variabele niet nul is. Dus, ervan uitgaande dat in ons vorige voorbeeld, het in feite was stadium
dat was nul
, we kunnen zoiets als dit doen:
if (someSprite.stage) myArray.push (someSprite.stage.align.toLowerCase ());
Deze test - if (someSprite.stage)
- zal terugkeren waar
als er een waarde is (ongeacht de waarde), en vals
als het is nul
. Over het algemeen werkt deze notatie; je kunt altijd gebruiken if (someSprite.stage! = null)
als je dat liever hebt. Aantal
s presenteren echter een iets andere situatie. Als het Aantal
heeft de waarde van 0
, dan heeft het technisch gezien een waarde, maar testen if (someNumberThatEqualsZero)
zal evalueren naar vals
. Voor Aantal
s u kunt de isNaN ()
functie om te bepalen of een geldige numerieke waarde is opgeslagen in een gegeven variabele.
In ieder geval is deze techniek een eenvoudige manier om de fout te omzeilen. Als de variabele waarop we een bewerking willen uitvoeren niet is ingesteld, voer dan de bewerking niet uit. Als er geen smakelijke drank in ons glas zit, neem het glas dan niet op. Simpel genoeg.
Maar die benadering is alleen mogelijk als de logica optioneel is. Als de logica vereist is, kunt u misschien een standaardwaarde opgeven voor de dubieuze variabele vóór de foutbewerking. Bijvoorbeeld, als myArray
heeft het potentieel om te zijn nul
, maar het is noodzakelijk dat dit niet zo is, we kunnen dit doen:
if (! myArray) myArray = []; myArray.push (someSprite.stage.align.toLowerCase ());
Dit zal eerst controleren om te zien of de array is nul
. Als dit het geval is, initialiseer je het in een lege array (een lege array is een geldige waarde. Het is mogelijk leeg, maar het is een array en niet nul
) voordat de geforceerde coderegel wordt uitgevoerd. Als het dat niet is nul
, sla direct over naar de gekunstelde regel code. Als het glas in het echt leeg is, vul het dan met een lekker drankje voordat je het opraapt.
Bovendien, als myArray
is een instantie-eigenschap van de klasse waarin deze regel code wordt uitgevoerd, u kunt redelijk veilig zorgen voor een geldige waarde door uw eigenschappen te initialiseren wanneer het object wordt geïnitialiseerd.
Wat als de logica vereist is, maar de variabele in kwestie niet zo gemakkelijk onder onze controle is? Bijvoorbeeld, wat als onze gekunstelde regel code vereist is, maar de dubieuze variabele is someSprite.stage
? We kunnen niet alleen de stadium
eigendom; die intern wordt beheerd naar DisplayObject
en is alleen-lezen voor gewone stervelingen. Dan moet je misschien sluw worden en de volgende stap lezen.
nul
stadiumEr zijn waarschijnlijk een oneindig aantal scenario's waarin een gegeven variabele of eigenschap zou kunnen zijn nul
. Het is duidelijk dat ik ze niet allemaal in een Quick Tip kan behandelen. Er is echter één specifieke situatie die steeds weer opduikt.
Laten we zeggen dat je een code schrijft die er zo uitziet:
openbare klasse QuickSprite breidt Sprite uit openbare functie QuickSprite () stage.addEventListener (MouseEvent.MOUSE_MOVE, onMove); private function onMove (e: MouseEvent): void var color: ColorTransform = new ColorTransform (); color.color = stage.mouseX / stage.stageWidth * 0xFFFFFF; this.transform.colorTransform = kleur;
Nog een gekunsteld stuk code (wat tot epileptische aanvallen zou kunnen leiden - beschouw jezelf als gewaarschuwd), maar eigenlijk is het idee dat je een sprite
subklasse en u stelt dit in als de klasse voor een clip op het werkgebied, met behulp van de Flash IDE.
U besluit echter dat u hiermee wilt werken QuickSprite
programmatisch. Dus je probeert dit:
var qs: QuickSprite = nieuwe QuickSprite (); addChild (qs);
En je krijgt de vervloekte Error 1009. Waarom? Omdat in de QuickSprite
constructor, krijgt u toegang tot de stadium
eigendom (geërfd van DisplayObject
). Wanneer het object volledig met code is gemaakt, bevindt het zich niet op het punt op het punt dat die regel code loopt, wat betekent stadium
is nul
en je krijgt de foutmelding. De QuickSprite
wordt de volgende regel toegevoegd, maar het is niet snel genoeg. Als de instantie wordt gemaakt door een symbool uit de bibliotheek naar het werkgebied te slepen, is er achter de schermen een beetje magie aan de gang die ervoor zorgt dat de instantie zich op het podium bevindt (dat wil zeggen, de stadium
eigenschap is ingesteld) tijdens de constructor.
Dus dit is wat je doet: je test op het bestaan van een waarde voor stadium
. Afhankelijk van het resultaat, kunt u de setup-code meteen uitvoeren of een andere gebeurtenislistener instellen voor wanneer QuickSprite
wordt wel toegevoegd aan het podium. Iets zoals dit:
openbare functie QuickSprite () if (stage) init (); else this.addEventListener (Event.ADDED_TO_STAGE, init); private function init (e: Event = null) this.removeEventListener (Event.ADDED_TO_STAGE, init); stage.addEventListener (MouseEvent.MOUSE_MOVE, onMove);
Als we het verplaatsen stadium
regel naar een andere functie, en alleen die functie aanroepen wanneer we een fase hebben, dan zijn we klaar. Als stadium
bestaat vanaf het begin, ga je gang en start in het()
meteen. Zo niet, dan gebruiken we in het()
als een gebeurtenis luisteraarfunctie voor ADDED_TO_STAGE
, op welk punt we een fase-waarde zullen hebben en de code kunnen uitvoeren. Nu kunnen we de klasse gebruiken voor het verbinden met IDE Sprite of volledig programmatisch.
Dit werkt ook goed in documentklassen. Wanneer u zelf een SWF uitvoert, heeft de documentklasse direct toegang tot stadium
. Als u die SWF echter in een andere SWF laadt, wordt de code in de initialisatiestack van de documentklasse uitgevoerd voordat de geladen SWF wordt toegevoegd aan de display. Een soortgelijke stadium
-Als u truc controleert, kunt u met de SWF werken als zowel een zelfstandig stuk als als een SWF die in een SWF-bestand wordt geladen.
Bedankt voor het lezen van deze snelle tip! Ik hoop dat je een beetje geïnformeerd bent over hoe Fout 1009 voorkomt en hoe je het kunt debuggen. Houd ons in de gaten voor meer Snelle tips over andere veelvoorkomende fouten.