The famous "Invalid native object" problem... but why?

Hello everyone.

After reading the post about why this error happens, I understood the reasons and tried to follow a pattern that would avoid what would cause this error. So, my classes are defined like the following (a simple example); all my structures for data are attributes of the classes. In this way I believe that, as long the instances “live”, there should be no reason for the error, right?

(function() {
    gameName.gamePlay.layers.SomeLayerClass = cc.Layer.extend({
        (... all attributes here, not as global vars ...)
        someSprite: null,
        (...)

	ctor: function() {
           this._super();
           this.initialize();
	},
	
	initialize: function() {
	}

        (....)
    });
})();

Please ignore my anonymous closure; I use it just to avoid public global variables and functions. :slight_smile:

Even though all the project follows this pattern, I still have the “Invalid native object” when, for example, I change between scenes (like, between the game-play and the menu scenes twice).

So, after checking about a know-issue of JSB, is it really necessary to retain() and release() even if I try to not let the reference count reach zero?

Thanks in advance.

I’m not sure how your code would prevent the “Invalid native object” error.

When you change scene, I believe that all of the nodes attached as children will be removed from their parents which will decrease their reference count by 1. If you have not used retain to increase the count, these objects will be destroyed. If you are still referencing them in your JavaScript code and trying to use them, you will get the “Invalid native object” error.

1 Like

Because all objects are not just global variables; in this case, there is no code elsewhere that would reference an object that was destroyed. I mean, all objects are created by their respective parent object and stored as attributes. Also, I keep the encapsulation (ok, at least trying to follow the principle in JS world :-)) so one object does not reference attributes of another.

If I had code locally in some stand alone functions or even global variables that would store object references, then it would make sense to have this error in some cases.

Or am I missing the point here?

Thank you for the reply.

Not sure why you would be getting the error when changing scene, unless somehow your scene wasn’t being destroyed when you change.

Which object is invalid?

So I believe cc.Layer.extend is used to create a “class” that inherits from Layer, but I think you still need to create objects using something like var obj = new MyClass();, if you had var MyClass = cc.Layer.extend({ ... }); So do you create instances of SomeLayerClass or do you use SomeLayerClass as an object itself?

The structure is the following:

I have a singleton object called sceneManager that instantiates scenes accordingly and calls cc.director to “run” them. The creation is, as you may guess, done like this:

fruitFarm.common.sceneManager = {
    gotoMainMenu: function() {
	cc.director.runScene(new fruitFarm.mainMenu.scenes.MainMenuScene());
    },

    gotoGamePlay: function() {
	cc.director.runScene(new fruitFarm.gamePlay.scenes.GamePlayScene());
    }
    (...)

Inside each scene class, I instantiate layer objects. For instance:

(function() {
    fruitFarm.mainMenu.scenes.MainMenuScene = cc.Scene.extend({
	backgroundLayer: null,
	menuLayer: null,
	
	ctor: function() {
		this._super();
		this.createLayers();
		this.initialize();
		this.registerEventListeners();
	},
	
	createLayers: function() {
		this.addChild(this.backgroundLayer = new fruitFarm.mainMenu.layers.BackgroundLayer());
		this.addChild(this.menuLayer = new fruitFarm.mainMenu.layers.MenuLayer());
	},
(...)

The same applies to layer classes which instantiates sprites.

Right, I see what you’re doing. I don’t use the anonymous closures so I’m not used to them.

Which object is throwing the “invalid native object” error?

Good news. After updating to version 3.3, I was not able to provoke the error… but if it comes again, I will post here exactly where it happens.

Well, I talked too early. It still happens and in two places (at least for now):

In the game there is a basket sprite to collect fruits. After switching from scenes (mainmenu -> gameplay -> mainmenu -> gameplay), the basket sprite causes the error in these two lines:

	initialize: function() {
		this.setPosition(cc.winSize.width / 2, 30); // <-- here
		this.xSpeed = 0;
	},

	rotateTo: function(angle) {
		this.stopAllActions(); // <--- and here
		var rotateAction = new cc.RotateTo(0.3, angle, angle);
		this.runAction(rotateAction);
	},

If I call retain() on this sprite, the error goes away. But I still believe that I am not allowing any object to be zero-referenced, so the retain() workaround should not be necessary.

The full source code of the basket sprite:

(function() {
    fruitFarm.gamePlay.sprites.BasketSprite = cc.Sprite.extend({
	xSpeed: null,
	
	ctor: function() {
		this._super(res.GamePlayBasket_png);
		this.initialize();
		this.registerEventListeners();
	},
	
	initialize: function() {
		this.setPosition(cc.winSize.width / 2, 30);
		this.xSpeed = 0;
	},
	
	moveLeft: function() {
		this.xSpeed -= fruitFarm.common.BASKET_SPEED;
		this.rotateTo(-20);
	},
	
	moveRight: function() {
		this.xSpeed += fruitFarm.common.BASKET_SPEED;
		this.rotateTo(20);
	},
	
	registerEventListeners: function() {
		var self = this;
		cc.eventManager.addCustomListener("onMoveLeft", function(event) {
			self.moveLeft();
		});
		cc.eventManager.addCustomListener("onMoveRight", function(event) {
			self.moveRight();
		});
		cc.eventManager.addCustomListener("onStop", function(event) {
			self.stop();
		});
	},
	
	rotateTo: function(angle) {
		this.stopAllActions();
		var rotateAction = new cc.RotateTo(0.3, angle, angle);
		this.runAction(rotateAction);
	},
	
	stop: function() {
		this.xSpeed = 0;
		this.rotateTo(0);
	},
	
	update: function(dt) {
		this._super(dt);			
		this.x += this.xSpeed;
	}
    });
})();

That code seems fine to me. If initialize is only called when the sprite is created created, then that seems quite strange it would fail within there. I’m not sure what could be happening.

You may have to do some isolation testing; commenting out code until the error goes away, or starting a fresh project and copying a part of your code you want to test into it to see if the code works.

P.S. I wrote some test code similar to yours, with an anonymous closure that create a class, and then code that instances that class. It worked for me, but I did find that if I excluded this._super(), I did get an Invalid native object error inside initialize when I tried to set the position of the sprite. You include it in ctor so this probably isn’t the error, but it’s the only way I can see the error being thrown while the object is being created.

1 Like

I see no problem in your code neither, what I can guess from your description is that, when you switch scenes, the sprites in the old scenes still get accessed after the switch, it may still exist in JS life cycle, but the native object have been released.

Ok, I have found one culprit and I will explain it here so I hope others can benefit from this. At least until now the problem was solved.

First I must admit it was a very subtle mistake of mine and indeed it allowed one reference to be lost due the way Javascript manages its life cycle. Here is the explanation:

In the code I register a lot of event listeners (keyboard, mouse, touch and custom listeners as well) but I did not explicitly unregister them! So, even though I create new scenes and the whole tree of objects in this process, the old objects (that should not exist anymore) are still referenced by the eventManager and stay in its notification list.

So, the error occured because the old objects got called by eventManager and, indeed, each of the corresponding native object was already destroyed.

The moral of the history: don’t trust GC or the JS life cycle; always unregister your event listeners yourself. In my case I chose to override onExit method, although I am not sure if this is the right place (I miss a destructor method…).

1 Like

Yes, onExit is indeed the right place to unregister the event listeners.

hello…i got errors too with Invalid Native Object

jsb: ERROR: File …\auto\jsb_cocos2dx_auto.cpp: Line: 4302, Function: js_cocos2dx_Node_getPositionX
js_cocos2dx_Node_getPositionX : Invalid Native Object

what is that mean? it just reference to file which is from frameworks folder. not my game folder