Tip: If you allow debugging, the exception will tell you the exact line in the source code where the Error is being thrown. Assuming you’re using the Flash IDE, go to publish settings and in the Flash tab check «Permit debugging». This will makes thing much easier for you.
Anyway, you have an error message. If you read it carefully, you can narrow down where the problem is. I don’t know if you are a programmer or you have any interest in being one; if you’re not, this answer will hopefully solve this particular problem. Anyway, if you don’t mind the rambling, let me tell you that if you’re interested in becoming a better programmer, paying attention to errors and learning how to debug / troubleshoot problems is one of the most important abilities you need to develop (if not the most important one); so maybe this will give you a few hints you can use to solve other problems as well.
The message says:
Cannot access a property or method of
a null object reference.
This means, at some point, you did something like this:
someobject.someMethod();
or
someobject.someProperty = "foo";
And someobject happened to be null. You can’t call methods or access properties of null.
Ok, so now you know, somewhere, a variable had null as its value. Notice that the fact that you define a variable of property doesn’t mean it actually holds an object.
This just says that a variable called mySprite can hold an object of the type Sprite:
var mySprite:Sprite;
But until at some point you create a Sprite and assign it to mySprite, the value held by mySprite will be null. If you do:
mySprite.x = 0;
Before initializing mySprite (i.e. before assigning a Sprite to it), you will have this same Null Reference error.
This error message also offers some helpul context, which you can use to your advantage (in them old days… errors in Flash were silent; when things didn’t work, you had to manually trace down the problem).
Ok, let’s break this error message down:
at com.senocular.utils::KeyObject/construct()
at com.senocular.utils::KeyObject()
at com.asgamer.basics1::Ship()
at com.asgamer.basics1::Engine()
What you have above is called a stack trace. It basically tells you where the code blew up, and also gives you some context: how did you get there.
The first line tells where the error actually occurred. That is, the construct method in the KeyObject object. That method was called from the KeyObject constructor, which was in turn called from the Ship constructor, which was in turn called from the Engine constructor.
Now, let’s analyze how you got there, following the stack trace, bottom-up:
Code in Engine constructor:
ourShip = new Ship(stage);
This creates a new Ship object. It passes a reference to the stage to the Ship constructor method.
Code in Ship constructor:
this.stageRef = stageRef;
key = new KeyObject(stageRef);
It grabs the ref passed in the previous step. It stores it and creates a new KeyObject object. The KeyObject constructor is passed a reference to the stage (which is the same ref that was passed from Engine to Ship).
Code in KeyObject constructor:
KeyObject.stage = stage;
keysDown = new Object();
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyPressed);
stage.addEventListener(KeyboardEvent.KEY_UP, keyReleased);
Now we got to the point where the error message told you the problem was. So, somewhere, you are using a variable that holds null and trying to access one of its methods or properties.
This KeyObject stores the reference to stage it was passed in a static variable and creates a new Object object. So far, no problems. KeyObject cannot be null (it’s a reference to a Class). The second line itself cannot have this null problem either. So, if this is all the code in that method, the problem has to be either in the third or the fourth line. Both access the stage reference you passed and try to call a method (addEventListener) on it. So if one fails, the other will fail as well. Then, the third line: that’s where the problem has to be.
So, at that point stage
is null. As said previously, you can’t call a method on null, and that’s what the error is telling you.
Now, if you get back to the first method call, you can see this is the origin of the problem:
ourShip = new Ship(stage);
You can be pretty sure that, at this point, stage was null. Add that to the fact that Engine extends MovieClip (which is in turn a DisplayObject), and to the fact that any DisplayObject has a reference to the stage object only while it’s added to the display list. The conclusion: an instance of Engine was not attached to the display list when its constructor was ran.
A way to fix this (there might be others) could be moving the code in the Engine constructor to a separate function that will be executed only if / when the Engine object has a valid reference to the stage object.
public function Engine() : void {
if(stage) {
initialize();
} else {
addEventListener(Event.ADDED_TO_STAGE,initialize);
}
}
private function initialize(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE,initialize);
// here goes the code that's currently in Engine constructor
}
Hope this helps.
One of the more common questions I see on forums and get from colleagues is how to debug Error 1009, also known as the “Null Object Reference Error.” Or, as I call it, the “Annoying Mosquito Error From Hell.” It crops up a lot, and unfortunately the error itself does not contain much information about the source of the error. In this quick tip, we’ll take a look at some steps you can take to track down this mosquito and squash it good.
Introduction
This piece is the first followup to the more general “Fixing Bugs in AS3” tutorial. If you wish to better understand some of the techniques in this tip, you may wish to read that in full first.
Step 1: Understand the Error
It’s too bad that Adobe doesn’t (or can’t) provide more information about the root of this error. First of all, it’s rather obtusely worded (much like all of their errors, but this more so than most):
TypeError: Error #1009: Cannot access a property or method of a null object reference
Let’s try to put this in everyday terms. Error 1009 means that you’ve tried to do something with a variable that you assume has a value, but really does not. Flash doesn’t like that. You wouldn’t like it either; imagine you had a glass that you assumed was full of the tasty beverage of your choice, but really was empty. You grab the glass, expecting a refreshing swig, but you feel the disappointing weight of an empty glass instead. That’s your own personal Error 1009.
In ActionScript, if you do this:
1 |
|
2 |
var s:String; |
3 |
trace(s.toUpperCase()); |
Flash will bum hard (a technical term for “produce an error”) when you run the code. The variable s
may have been declared, but its value is null
(we never set the value, just declared the variable), so calling the toUpperCase
method on it is troublesome.
To be clear, because s
is declared as a String
, the compiler takes no issue with the code: there is a variable called s
, it’s a String
, and toUpperCase
is a valid method to call on String
s. The error we get is a run-time error, which means we only get it when we run the SWF. Only when the logic is performed do we now get to see how this turns out.
Step 2: Permit Debugging
As with any run-time error, sometimes it’s pretty easy to tell what’s going on without any extra information. But other times it’s helpful to narrow this down further. At this point, try turning on “Permit Debugging.” When this is enabled, you get errors that also give you line numbers. Alternatively, you may be able to “Debug Movie” by pressing Command-Shift-Return / Control-Shift-Enter.
To do so, see the general debugging tips article, “Fixing Bugs in AS3”
Sometimes this is enough. Knowing the specific line might be all the information you needed. If not, we’ll dig a little deeper in the next step.
Our dear editor, Michael James Williams, encapsulated the point of this step in a limerick, which I’m happy to present to you now with his kind permission:
AS3 error one-oh-oh-nine
Is never a very good sign.
No need for concern,
Hit Ctrl-Shift-Return
And it’ll pinpoint the cause (well, the line).
Step 3: Start Tracing
If you’ve located the offending line but are still unsure what’s going on, pick apart the line. Take every variable in that line and trace them out prior to the error.
Because the error comes when accessing a property or calling a method on a null variable, to cover your bases you should trace any variables and properties that are immediately followed by a dot. For example, take this line of code:
1 |
|
2 |
myArray.push(someSprite.stage.align.toLowerCase()); |
Admittedly, that’s a rather contrived piece of code that I can’t imagine a practical use for, but you should identify four total possible null
values that are being accessed with the dot:
-
myArray
: we are calling thepush
method on this variable -
someSprite
: we are accessing thestage
property -
stage
: we are accessing thealign
property -
align
: we are calling thetoLowerCase
method
So your debugging code might look like this:
1 |
|
2 |
trace("myArray: ", myArray); |
3 |
trace("someSprite: ", someSprite); |
4 |
trace("someSprite.stage: ", someSprite.stage); |
5 |
trace("someSprite.stage.align: ", someSprite.stage.align); |
Order is important; if someSprite
is the null object, but you test for someSprite.stage.align
before testing for someSprite
, you end up with less definitive results.
Now, common sense also plays into this. In my example, if stage
exists, then align
will most assuredly have a value; the Stage
always has an align
setting, even if it’s the default value.
Typically, you’ll see something like the following:
1 |
|
2 |
myArray: [...stuff in the array...] |
3 |
someSprite: [object Sprite] |
4 |
someSprite.stage: null |
5 |
Error #1009: ... |
Which should clue you in that the stage
property is null
, and now you can go about fixing it.
Step 4: Finding a Solution
The easiest solution is to wrap up the offending statement in an “if” block, and only run the block if the variable in question is not null. So, assuming that in our previous example, it was in fact stage
that was null
, we could do something like this:
1 |
|
2 |
if (someSprite.stage) { |
3 |
myArray.push(someSprite.stage.align.toLowerCase()); |
4 |
}
|
This test — if (someSprite.stage)
— will return true
if there is a value (regardless of the value), and false
if it’s null
. In general this notation works; you can always use if (someSprite.stage != null)
if you prefer. Number
s present a slightly different situation, though. If the Number
has a value of 0
, then technically it has a value, but testing if (someNumberThatEqualsZero)
will evaluate to false
. For Number
s you can use the isNaN()
function to determine if a valid numeric value is stored in a given variable.
At any rate, this technique is a simple way to sidestep the error. If the variable we want to perform an operation on is not set, then don’t do the operation. If there is no tasty beverage in our glass, don’t pick up the glass. Simple enough.
But that approach is only feasible if the logic is optional. If the logic is required, then perhaps you can provide a default value to the questionable variable before the error-ing operation. For example, if myArray
has the potential to be null
, but it’s imperative that it’s not, we can do this:
1 |
|
2 |
if (!myArray) { |
3 |
myArray = []; |
4 |
}
|
5 |
myArray.push(someSprite.stage.align.toLowerCase()); |
This will first check to see if the array is null
. If it is, initialize it to an empty array (an empty array is a valid value. It may be empty, but it’s an array, and not null
) before running the contrived line of code. If it’s not null
, skip straight to the contrived line of code. In real-life terms, if our glass is empty, then fill it with a tasty beverage before picking it up.
In addition, if myArray
is an instance property of the class in which this line of code is running, you can pretty safely ensure a valid value by initializing your properties when the object initializes.
What if the logic is required, but the variable in question is not so readily under our control? For example, what if our contrived line of code is required, but the questionable variable is someSprite.stage
? We can’t just set the stage
property; that’s controlled internally to DisplayObject
and is read-only to us mere mortals. Then you may need to get crafty, and read the next step.
Step 5: Dealing with a null
stage
There are probably an infinite number of scenarios where a given variable or property could be null
. Obviously, I can’t cover them all in a Quick Tip. There is one specific situation, however, that crops up again and again.
Let’s say you write some code that looks like this:
1 |
|
2 |
public class QuickSprite extends Sprite { |
3 |
public function QuickSprite() { |
4 |
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMove); |
5 |
}
|
6 |
private function onMove(e:MouseEvent):void { |
7 |
var color:ColorTransform = new ColorTransform(); |
8 |
color.color = stage.mouseX / stage.stageWidth * 0xFFFFFF; |
9 |
this.transform.colorTransform = color; |
10 |
}
|
11 |
}
|
Another contrived bit of code (which might induce seizures — consider yourself warned), but basically the idea is that you have a Sprite
subclass and you set this as the class for a clip on the stage, using the Flash IDE.
However, you decide you want to work with these QuickSprite
s programmatically. So you try this:
1 |
|
2 |
var qs:QuickSprite = new QuickSprite(); |
3 |
addChild(qs); |
And you get the accursed Error 1009. Why? Because in the QuickSprite
constructor, you access the stage
property (inherited from DisplayObject
). When the object is created entirely with code, it is not on the stage at the point that that line of code runs, meaning stage
is null
and you get the error. The QuickSprite
gets added the very next line, but it’s not soon enough. If the instance is created by dragging a symbol out of the library and onto the stage, then there’s a little bit of magic at work behind the scenes that ensure that the instance is on the stage (that is, the stage
property is set) during the constructor.
So here’s what you do: you test for the existence of a value for stage
. Depending on the result, you can either run the set up code right away, or set up a different event listener for when the QuickSprite
does get added to the stage. Something like this:
1 |
|
2 |
public function QuickSprite() { |
3 |
if (stage) { |
4 |
init(); |
5 |
} else { |
6 |
this.addEventListener(Event.ADDED_TO_STAGE, init); |
7 |
}
|
8 |
}
|
9 |
private function init(e:Event=null) { |
10 |
this.removeEventListener(Event.ADDED_TO_STAGE, init); |
11 |
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMove); |
12 |
}
|
If we move the stage
line to a different function, and only call that function when we have a stage, then we’re set. If stage
exists from the start, go ahead and run init()
right away. If not, we’ll use init()
as an event listener function for ADDED_TO_STAGE
, at which point we will have a stage value and can run the code. Now we can use the class for either connecting to IDE Sprite or completely programmatically.
This works well in document classes, too. When you run a SWF by itself, the document class has immediate access to stage
. If you load that SWF into another SWF, though, the code in the document class’s initialization stack gets executed before the loaded SWF is added to the display. A similar stage
-checking trick will allow you to work with the SWF as both a standalone piece and as a SWF loaded into a containing SWF.
That Is All
Thanks for reading this Quick Tip! I hope you are enlightened a bit about how Error 1009 occurs, and how you can debug it. Stay tuned for more Quick Tips on other common errors.
Один из наиболее распространенных вопросов, которые я вижу на форумах и получаю от коллег, – как отлаживать ошибку 1009, также известную как «ошибка ссылки на нулевой объект». Или, как я ее называю, «досадная ошибка москита из ада». вверх, и, к сожалению, сама ошибка не содержит много информации об источнике ошибки. В этом кратком совете мы рассмотрим некоторые шаги, которые вы можете предпринять, чтобы выследить этого комара и хорошо его раздавить.
Вступление
Этот фрагмент является первым продолжением более общего руководства «Исправление ошибок в AS3» . Если вы хотите лучше понять некоторые приемы, описанные в этом совете, вы можете сначала прочитать их полностью.
Шаг 1: понять ошибку
Жаль, что Adobe не предоставляет (или не может) предоставить дополнительную информацию о причинах этой ошибки. Прежде всего, это довольно тупо сформулировано (как и все их ошибки, но это больше, чем большинство):
Ошибка типа: ошибка № 1009: невозможно получить доступ к свойству или методу ссылки на пустой объект
Давайте попробуем изложить это в повседневных условиях. Ошибка 1009 означает, что вы пытались что-то сделать с переменной, которая, как вы предполагаете, имеет значение, но на самом деле это не так. Flash не нравится это. Тебе это тоже не понравится; представьте, что у вас был стакан, который, как вы предполагали, был полон вкусного напитка по вашему выбору, но на самом деле был пуст. Вы хватаете стакан, ожидая освежающего глотка, но вместо этого вы чувствуете удручающий вес пустого стакана. Это ваша личная ошибка 1009.
В ActionScript, если вы делаете это:
1 2 |
var s:String; trace(s.toUpperCase()); |
При запуске кода Flash будет работать очень быстро (технический термин «выдает ошибку»). Переменная s
может быть объявлена, но ее значение равно null
(мы никогда не устанавливали значение, просто объявляли переменную), поэтому вызов метода toUpperCase
для нее проблематичен.
Для ясности, поскольку s
объявлен как String
, компилятор не имеет проблем с кодом: есть переменная с именем s
, это String
, а toUpperCase
является допустимым методом для вызова на String
s. Ошибка, которую мы получаем, является ошибкой во время выполнения , что означает, что мы получаем ее только при запуске SWF. Только когда логика выполнена, мы можем теперь увидеть, как это получается.
Шаг 2: Разрешить отладку
Как и в случае любой ошибки во время выполнения, иногда довольно легко сказать, что происходит, без какой-либо дополнительной информации. Но в других случаях полезно сузить это дальше. На этом этапе попробуйте включить «Разрешить отладку». Когда эта опция включена, вы получаете ошибки, которые также дают номера строк. Кроме того, вы можете «Отладить фильм», нажав Command-Shift-Return / Control-Shift-Enter.
Для этого см. Общую статью с советами по отладке «Исправление ошибок в AS3».
Иногда этого достаточно. Знание конкретной строки может быть всей необходимой вам информацией. Если нет, мы углубимся в следующий шаг.
Наш дорогой редактор, Майкл Джеймс Уильямс, изложил смысл этого шага в известной статье, которую я с радостью представляю вам сейчас с его любезного разрешения:
Ошибка AS3 один-о-о-девять
Никогда не очень хороший знак.
Не нужно беспокоиться,
Хит Ctrl-Shift-Return
И это точно определит причину (ну, линию).
Шаг 3: Начните трассировку
Если вы обнаружили нарушающую линию, но все еще не знаете, что происходит, выделите ее. Возьмите каждую переменную в этой строке и проследите их до ошибки.
Поскольку ошибка возникает при доступе к свойству или при вызове метода с нулевой переменной, для покрытия ваших баз вы должны отслеживать любые переменные и свойства, за которыми сразу следует точка. Например, возьмем эту строку кода:
1 |
myArray.push(someSprite.stage.align.toLowerCase()); |
Следует признать, что это довольно надуманный кусок кода, для которого я не представляю практического применения, но вы должны определить четыре возможных null
значения, к которым обращаются с помощью точки:
-
myArray
: мы вызываем методpush
для этой переменной -
someSprite
: мы получаем доступ к свойствуstage
-
stage
: мы получаем доступ к свойствуalign
-
align
: мы вызываем методtoLowerCase
Таким образом, ваш код отладки может выглядеть так:
1 2 3 4 |
trace(“myArray: “, myArray); trace(“someSprite: “, someSprite); trace(“someSprite.stage: “, someSprite.stage); trace(“someSprite.stage.align: “, someSprite.stage.align); |
Порядок важен; если someSprite
является нулевым объектом, но вы проверяете someSprite.stage.align
перед тестированием someSprite
, вы получите менее someSprite
результаты.
Теперь здравый смысл также играет в этом. В моем примере, если stage
существует, align
будет, безусловно, значение; Stage
всегда имеет настройку align
, даже если это значение по умолчанию.
Как правило, вы увидите что-то вроде следующего:
1 2 3 4 |
myArray: […stuff in the array…] someSprite: [object Sprite] someSprite.stage: null Error #1009: … |
Что должно указывать на то, что свойство stage
имеет значение null
, и теперь вы можете исправить его.
Шаг 4: Поиск решения
Самое простое решение – заключить ошибочный оператор в блок if и запускать блок только в том случае, если рассматриваемая переменная не равна нулю. Итак, предполагая, что в нашем предыдущем примере это была фактически null
stage
, мы могли бы сделать что-то вроде этого:
1 2 3 |
if (someSprite.stage) { myArray.push(someSprite.stage.align.toLowerCase()); } |
Этот тест – if (someSprite.stage)
– вернет true
если есть значение (независимо от значения), и false
если оно равно null
. В целом эта запись работает; вы всегда можете использовать if (someSprite.stage != null)
если хотите. Number
s представляет немного другую ситуацию, хотя. Если Number
имеет значение 0
, то технически оно имеет значение, но проверка if (someNumberThatEqualsZero)
оценивается как false
. Для Number
s вы можете использовать isNaN()
чтобы определить, хранится ли допустимое числовое значение в данной переменной.
В любом случае, эта техника – простой способ обойти ошибку. Если переменная, с которой мы хотим выполнить операцию, не установлена, не делайте эту операцию. Если в нашем стакане нет вкусного напитка, не поднимайте его. Достаточно просто.
Но такой подход возможен только в том случае, если логика является необязательной. Если логика требуется, то, возможно, вы можете указать значение по умолчанию для сомнительной переменной перед операцией ошибки. Например, если myArray
потенциально может быть null
, но обязательно, чтобы это было не так, мы можем сделать это:
1 2 3 4 |
if (!myArray) { myArray = []; } myArray.push(someSprite.stage.align.toLowerCase()); |
Сначала будет проверено, является ли массив null
. Если это так, инициализируйте его пустым массивом (пустой массив является допустимым значением. Он может быть пустым, но это не массив, а массив) перед запуском надуманной строки кода. Если он не null
, перейдите прямо к надуманной строке кода. В реальных условиях, если наш стакан пуст, то наполните его вкусным напитком, прежде чем поднять его.
Кроме того, если myArray
является свойством экземпляра класса, в котором выполняется эта строка кода, вы можете довольно безопасно обеспечить допустимое значение, инициализируя свои свойства при инициализации объекта.
Что если логика требуется, но рассматриваемая переменная не так легко находится под нашим контролем? Например, что, если требуется наша искусственная строка кода, но сомнительной переменной является someSprite.stage
? Мы не можем просто установить свойство stage
; это внутренне контролируется DisplayObject
и DisplayObject
только для нас, простых смертных. Тогда вам может понадобиться стать хитрым и прочитать следующий шаг.
Шаг 5: Работа с null
стадией
Вероятно, существует бесконечное количество сценариев, в которых данная переменная или свойство могут быть null
. Очевидно, я не могу охватить их все в кратком совете. Однако есть одна конкретная ситуация, которая возникает снова и снова.
Допустим, вы пишете некоторый код, который выглядит следующим образом:
01 02 03 04 05 06 07 08 09 10 |
public class QuickSprite extends Sprite { public function 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 = color; } } |
Еще один надуманный фрагмент кода (который может вызвать приступы – считайте, что вас предупредили), но в основном идея заключается в том, что у вас есть подкласс Sprite
и вы устанавливаете его как класс для клипа на сцене, используя Flash IDE.
Однако вы решаете, что хотите работать с этими QuickSprite
программно. Итак, вы попробуйте это:
1 2 |
var qs:QuickSprite = new QuickSprite(); addChild(qs); |
И вы получите проклятую ошибку 1009. Почему? Потому что в конструкторе QuickSprite
вы QuickSprite
доступ к свойству stage
(унаследованному от DisplayObject
). Когда объект создается полностью с помощью кода, он не находится на стадии в тот момент, когда выполняется эта строка кода, что означает, что stage
имеет значение null
и вы получите ошибку. QuickSprite
добавляется в следующую строку, но это не достаточно скоро. Если экземпляр создается путем перетаскивания символа из библиотеки на сцену, то за кулисами работает немного магии, которая гарантирует, что экземпляр находится на сцене (то есть свойство stage
установлено) во время конструктор
Итак, вот что вы делаете: вы проверяете наличие значения для stage
. В зависимости от результата, вы можете сразу запустить настроенный код или настроить другой приемник событий, когда QuickSprite
будет добавлен на сцену. Что-то вроде этого:
01 02 03 04 05 06 07 08 09 10 11 |
public function 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); } |
Если мы переместим линию stage
в другую функцию и вызовем эту функцию только тогда, когда у нас есть сцена, тогда мы настроены. Если stage
существует с самого начала, продолжайте и сразу же запустите init()
. Если нет, мы будем использовать init()
в качестве функции прослушивания событий для ADDED_TO_STAGE
, после чего у нас будет сценическое значение и мы сможем выполнить код. Теперь мы можем использовать класс для подключения к IDE Sprite или полностью программно.
Это хорошо работает и в классах документов. Когда вы сами запускаете SWF, класс документа имеет немедленный доступ к stage
. Если вы загрузите этот SWF-файл в другой SWF-файл, код в стеке инициализации класса документа будет выполнен до того, как загруженный SWF-файл будет добавлен на экран. Подобный трюк с проверкой stage
позволит вам работать с SWF как с автономной частью, так и с SWF, загруженным в содержащий SWF.
Это все
Спасибо за чтение этого Быстрого Подсказки! Я надеюсь, что вы немного осведомлены о том, как происходит ошибка 1009, и как вы можете ее отладить. Оставайтесь с нами, чтобы узнать больше подсказок о других распространенных ошибках.
Вступление
Ошибка 1009 — это общая ошибка, возникающая при попытке получить значение из переменной или свойства с null
значением. Приведенные примеры вызывают различные случаи возникновения этой ошибки вместе с некоторыми рекомендациями по устранению ошибки.
замечания
Страшный и часто задаваемый вопрос «Ошибка 1009: невозможно получить доступ к свойству или методу ссылки на нулевой объект» — это сигнал о том, что некоторые данные отображаются нулевыми, но их пытаются использовать в качестве заселенного объекта. Есть довольно много типов проблем, которые могут вызвать это поведение, и каждый из них должен быть протестирован против кода, где возникла ошибка.
Этап недоступен
Иногда разработчики пишут код, который хочет получить доступ к stage
, или к stage
Flash, чтобы добавить слушателей. Он может работать в первый раз, а затем внезапно не работает и создает ошибку 1009. Этот код может быть даже на временной шкале, так как это первая инициатива по добавлению кода там, и многие учебники, которые все еще существуют, используют слот кода временной шкалы для размещения кода.
public class Main extends MovieClip {
public function Main() {
stage.addEventListener(Event.ENTER_FRAME,update); // here
Причина, по которой этот код не работает, прост: сначала создается экземпляр экранного объекта, затем добавляется в список отображения, а пока он не отображается в списке отображения, stage
имеет значение null.
Хуже, если код выглядит следующим образом:
stage.addEventListener(Event.ENTER_FRAME,update); // here
размещается на временной шкале. Он может даже работать некоторое время, в то время как Main
объект удаляется на сцену через графический интерфейс. Затем их SWF загружается из другого SWF, и внезапно код прерывается. Это происходит потому, что кадры Main
создаются по-другому, когда SWF загружается непосредственно игроком и когда загрузка обрабатывается асинхронно. Решение состоит в том, чтобы использовать прослушиватель Event.ADDED_TO_STAGE
и поместить весь код, который обращается к нему, и поместить сам прослушиватель в AS-файл вместо временной шкалы.
Недопустимый тип
function listener(e:Event):void {
var m:MovieClip=e.target as MovieClip;
m.x++;
}
Если такой прослушиватель прикреплен к объекту, который не является потомком MovieClip
(например, Sprite
), то при неудачном провале будет проигнорировано, и любые последующие операции с его результатом будут вызывать ошибку 1009.
Неинтересный объект
var a:Object;
trace(a); // null
trace(a.b); // Error 1009
Здесь ссылка на объект объявляется, но никогда не назначается значение, будь то с new
или присваиванием ненулевого значения. Запрос его свойств или метода приводит к ошибке 1009.
Многоуровневое выражение
x=anObject.aProperty.anotherProperty.getSomething().data;
Здесь любой объект до точки может оказаться нулевым, а использование методов, возвращающих сложные объекты, только увеличивает сложность для отладки нулевой ошибки. Худший случай, если метод подвержен посторонним отказам, скажем, получение данных по сети.
Результат необработанной функции
s=this.getChildByName("garbage");
if (s.parent==this) {...}
getChildByName()
является одной из многих функций, которые могут возвращать значение null, если возникла ошибка при обработке его ввода. Поэтому, если вы получаете объект из любой функции, которая может возвращать значение null, сначала проверьте значение null. Здесь свойство немедленно запрашивается без предварительной проверки, если s
равно null, это приведет к ошибке 1009.
Забытый слушатель событий
addEventListener(Event.ENTER_FRAME,moveChild);
function moveChild(e:Event):void {
childMC.x++;
if (childMC.x>1000) {
gotoAndStop(2);
}
}
В этом примере будет перемещен childMC
(добавлен в Main
во время разработки), но сразу же будет gotoAndStop()
1009, как только будет gotoAndStop()
, если этот childMC
не существует во фрейме 2. Основная причина этого заключается в том, что всякий раз, ключевой кадр (кадр, который не наследует набор объектов предыдущего кадра), либо с использованием gotoAndStop()
, gotoAndPlay()
с кадром назначения, отделенным от текущего кадра ключевым фреймом, либо обычным воспроизведением, если SWF является анимация, содержимое текущего кадра уничтожается, а новое содержимое создается с использованием данных, хранящихся в графическом интерфейсе. Таким образом, если новый кадр не имеет дочернего childMC
именем childMC
, запрос свойства возвращает null, а 1009 будет childMC
.
Тот же принцип применяется, если вы добавляете двух слушателей событий, но удаляете только один или добавляете слушателя к одному объекту, но пытаетесь удалить из другого. removeEventListener
не будет предупреждать вас, если объект не имеет соответствующего removeEventListener
событий, поэтому прочитайте код, который добавляет и удаляет прослушиватели событий.
Также обратите внимание: использование объектов Timer
вызове setInterval()
и setTimeout()
также создает прослушиватели событий, и они также должны быть очищены должным образом.
Недействительная ссылка на объект на основе кадра
Иногда gotoAndStop()
вызывается в середине кода, который ссылается на некоторые свойства на основе кадра. Но сразу же после изменения рамки все ссылки на свойства, существующие в текущем фрейме, недействительны, поэтому любая обработка, которая их включает, должна быть немедленно прекращена.
Существует два общих сценария такой обработки: во-первых, цикл не заканчивается после gotoAndStop()
, как здесь:
for each (bullet in bullets) {
if (player.hitTestObject(bullet)) gotoAndStop("gameOver");
}
Здесь ошибка 1009 означает, что player
MC был уничтожен во время обработки gotoAndStop()
, но цикл продолжается и ссылается на ссылку now-null, чтобы получить hitTestObject()
. Если условие скажет if (bullet.hitTestObject(player))
, ошибка будет # 2007 «Параметр hitTestObject не должен быть нулевым». Решение состоит в том, чтобы поставить оператор return
сразу после вызова gotoAndStop()
.
Второй случай — это несколько прослушивателей событий в одном и том же событии. Как это:
stage.addEventListener(Event.ENTER_FRAME,func1);
stage.addEventListener(Event.ENTER_FRAME,func2);
function func1(e:Event):void {
if (condition()) {
gotoAndStop(2);
}
}
Здесь, если condition()
истинно, первый прослушиватель выполнил бы gotoAndStop()
, но второй слушатель все равно будет выполнен, и если он ссылается на объекты в кадре, будет вызвана ошибка 1009. Решение состоит в том, чтобы избежать нескольких прослушивателей в одном событии, в одном объекте, лучше иметь один прослушиватель, который обрабатывает все ситуации на этом событии и может нормально завершаться, если требуется изменение фрейма.
Introduction
An error 1009 is a general error that arises when you are trying to receive a value out of a variable or property that has a value of null
. The examples provided expose various cases where this error arises, together with some recommendations on how to mitigate the error.
The dreaded and often asked «Error 1009: Cannot access a property or method of a null object reference» is a signal that some of the data appears null, but is tried to be used as a populated object. There are pretty many types of issues that can cause this behavior, and each one should be tested against the code where the error arised.
Stage is unavailable
Sometimes developers write some code that desires access to stage
, or Flash stage, to add listeners. It can work for the first time, then all of a sudden fail to work and produce the error 1009. The code in question can even be on the timeline, as it’s the first initiative to add code there, and many tutorials that still exist use timeline code layer to place the code.
public class Main extends MovieClip {
public function Main() {
stage.addEventListener(Event.ENTER_FRAME,update); // here
The reason this code doesn’t work is simple: A display object is first instantiated, then added to the display list, and while it’s off the display list, stage
is null.
Worse if the code like this:
stage.addEventListener(Event.ENTER_FRAME,update); // here
is placed on the timeline. It can even work for some time, while the Main
object is slapped to stage via GUI. Then, their SWF is loaded from another SWF, and all of a sudden the code breaks. This happens because the Main
‘s frames are constructed in a different way when the SWF is loaded directly by the player and when the loading is processed asynchronously. The solution is to use Event.ADDED_TO_STAGE
listener, and put all code that addresses stage in it, and put the listener itself into an AS file instead of the timeline.
Invalid typecast
function listener(e:Event):void {
var m:MovieClip=e.target as MovieClip;
m.x++;
}
If such a listener is attached to an object that’s not a MovieClip
descendant (for example, a Sprite
), the typecast will fail, and any subsequent operations with its result will throw the 1009 error.
Uninstantiated object
var a:Object;
trace(a); // null
trace(a.b); // Error 1009
Here, an object reference is declared, but is never assigned a value, be it with new
or assignment of a non-null value. Requesting its properties or method results in a 1009 error.
Multi-tiered expression
x=anObject.aProperty.anotherProperty.getSomething().data;
Here, any object before the dot can end up being null, and using methods that return complex objects only increases the complication to debug the null error. Worst case if the method is prone to extraneous failures, say retrieving data over the network.
Unprocessed function result
s=this.getChildByName("garbage");
if (s.parent==this) {...}
getChildByName()
is one of the many functions that can return null if an error occurred when processing its input. Therefore, if you are receiving an object from any function that can possibly return null, check for null first. Here, a property is instantly queried without first checking if s
is null, this will generate the 1009 error.
Forgotten event listener
addEventListener(Event.ENTER_FRAME,moveChild);
function moveChild(e:Event):void {
childMC.x++;
if (childMC.x>1000) {
gotoAndStop(2);
}
}
This example will move the childMC
(added to Main
at design time) but will instantly throw a 1009 as soon as gotoAndStop()
is invoked, if that childMC
does not exist on frame 2. The primary reason for this is that whenever a playhead passes a key frame (a frame which doesn’t inherit the previous frame’s object set), either by using gotoAndStop()
, gotoAndPlay()
with destination frame being separated from the current frame by a keyframe, or by normal play if the SWF is an animation, the current frame’s contents are destroyed and the new contents are created using the data stored from GUI. So, if the new frame does not have a child named childMC
, the property request will return null and 1009 will be thrown.
The same principle applies if you add two event listeners, but remove only one, or add a listener to one object, but try removing from another. The removeEventListener
call won’t warn you if the object did not have a respective event listener attached, so read the code that adds and removes event listeners carefully.
Note also: Using Timer
objects, calling setInterval()
and setTimeout()
also creates event listeners, and these should also be cleared properly.
Invalidated reference to a frame-based object
Sometimes gotoAndStop()
is called in the middle of the code that refers some frame-based properties. But, right after the frame is changed all links to properties that existed on the current frame are invalidated, so any processing that involves them should be immediately terminated.
There are two general scenarios of such processing to occur: First, a loop doesn’t end after gotoAndStop()
call, like here:
for each (bullet in bullets) {
if (player.hitTestObject(bullet)) gotoAndStop("gameOver");
}
Here, a 1009 error means that the player
MC was destroyed while processing gotoAndStop()
call, but the loop continues, and refers the now-null link to get hitTestObject()
from. If the condition would say if (bullet.hitTestObject(player))
instead, the error would be #2007 «Parameter hitTestObject must not be null». The solution is to put a return
statement right after calling gotoAndStop()
.
Second case is multiple event listeners on the same event. Like this:
stage.addEventListener(Event.ENTER_FRAME,func1);
stage.addEventListener(Event.ENTER_FRAME,func2);
function func1(e:Event):void {
if (condition()) {
gotoAndStop(2);
}
}
Here, if condition()
is true, the first listener would perform gotoAndStop()
, but the second listener would still be executed, and if that one references objects on the frame, a 1009 error will be thrown. The solution is to avoid multiple listeners on a single event, in a single object, it’s better to have one listener that handles all situations on that event and can properly terminate if a frame change is needed.
В процессе разработки игры я создал кнопку переключения между локальной/глобальной таблицей рекордов* и прилепил к ней такой код:
ActionScript 3 | ||
|
Всё бы ничего, но при дальнейшей проверке, в окно трейса начала выскакивать ошибка #1009.
Кликните здесь для просмотра всего текста
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at main_fla::MainTimeline/frame4()
at flash.display::Sprite/constructChildren()
at flash.display::Sprite()
at flash.display::MovieClip()
at main_fla::localizator_18()
at flash.display::MovieClip/gotoAndPlay()
at main_fla::MainTimeline/leaderboard()
Самое интересное, что при перенесении этого скрипта(и целого кадра) в другой проект, ошибка не появляется.
Кому надо, полный скрипт данного кадра:
Кликните здесь для просмотра всего текста
ActionScript 3 | ||
|
На кнопке никаких скриптов не стоит.
Как исправить эту ошибку?
__________________________________________________ __________________________________________________ __
*Для того, чтобы не возиться с событиями, я собрал её как мувиклип, внутри которого находятся 2 кнопки(см. скриншот ниже).
__________________
Помощь в написании контрольных, курсовых и дипломных работ, диссертаций здесь
#class #actionscript-3
#класс #actionscript-3
Вопрос:
Я создал класс для видеоролика, создающего монеты, которые игрок (символ) должен забрать. Предполагается, что все, что должен делать класс, это добавлять переменные score и coinscollected, а затем удалять одну монету со сцены. Но когда я меняю фрейм с помощью gotoAndStop(#);
, консоль отправляет спам
Тип ошибки: ошибка # 1009: не удается получить доступ к свойству или методу нулевой ссылки на объект. «
Класс монет:
public class coin extends MovieClip{
var char:MovieClip;
var MainTimeLine = MovieClip(root);
public function coin() {
// constructor code
this.addEventListener(Event.ENTER_FRAME,update);
}
function update(event:Event):void{
if(MainTimeLine.currentFrame!=5){
char=MovieClip(root).char;
if(this.hitTestObject(char)){
this.removeEventListener(Event.ENTER_FRAME,update);
parent.removeChild(this);
MainTimeLine.score ;
MainTimeLine.coinscollected ;
}
}
}
}
Комментарии:
1. Просто совет по лучшей практике чтения кода. Используйте первую букву в верхнем регистре для КЛАССОВ и первую букву в нижнем регистре для имен экземпляров / переменных. Так что в вашем случае
coin
должно бытьCoin
иMainTimeLine
должно бытьmainTimeLine
. Это также помогает с подсветкой кода в stackoverflow2. Вы можете либо исправить эту ошибку, либо проигнорировать ее с помощью инструкции try / catch ( действительно плохая практика). Кроме того, проигрыватель может запутаться, если вы пишете имена переменных с заглавной буквы.
3. Монета анимирована? В этом случае вам также следует выполнить функцию
stop()
перед ее удалением. Кроме того, в какой строке эта ошибка? Кроме того, вы должны изменитьvar char:MovieClip
значение простоvar char
так, чтобы оно не было нулевым. (Имейте в виду, что все функции и переменные должны быть в верблюжьем корпусе.)
Ответ №1:
Корень не заполняется до тех пор, пока ваш отображаемый объект не будет добавлен в список отображения. Вам нужно прослушать это событие, прежде чем устанавливать переменную.
var char:MovieClip;
var MainTimeLine; //do not initialize here, root is null at this point
public function coin() {
// constructor code
//root is still null here sometimes too, so see if it's populated yet
if(root){
init(); //root is populated, skip to initialization
}else{
this.addEventListener(Event.ADDED_TO_STAGE,addedToStage); //root isn't populated yet, listen for added to stage and then initialize
}
}
private function addedToStage(e:Event = null):void {
this.removeEventListener(Event.ADDED_TO_STAGE,addedToStage);
init();
}
private function init():void {
MainTimeLine = MovieClip(root)
this.addEventListener(Event.ENTER_FRAME,update);
}
Комментарии:
1. Большое вам спасибо за ваш ответ, но я только что понял, что мне следовало подробнее остановиться на ошибке. Ошибка 1009 указывает на «монету / обновление ()».
2. Ответ остается в силе. Вот где это приведет к ошибке, потому что именно там вы пытаетесь использовать свой
MainTimeLine
var, который был установленnull
.