I have a class that is a subclass of CCLayer. I found if I call setTouchEnabled(true), the destructor never gets called when my class is removed and cleaned up. If I don’t call setTouchEnabed, the destructor is called properly and everything is cleaned up.
By the way I’m using version 2.0.3 and this behavior occurs on both the simulator and device.
Designed as this. setTouchEnabled(true) will register this node into CCTouchDispatcher as a standard delegate. CCTouchDispatcher will add this node’s reference count. The same case happens to setKeypadEnabled(bool) and setAccelerometerEnabled(bool).
The best practice is to call setXxxEnabled(false) in MyCustomLayer::onExit()
Thanks for your reply Walzer and for responding so quickly!
I tried your suggestion of calling setTouchEnabled(false) in the onExit() method of my class, but that did not seem to help. When I walked through Cocos2D-X source code, I see that CCLayer::onExit() does remove the delegate. But for some reason my destructor still does not get called.
Here is a simple class I created to demonstrate the issue.
TestLayer::~TestLayer()
{
// this never gets called
CCLOG("TestLayer::~TestLayer() called");
}
TestLayer* TestLayer::create()
{
TestLayer* pRet = new TestLayer();
if (pRet && pRet->init()) {
pRet->autorelease();
return pRet;
}
CC_SAFE_DELETE(pRet);
return NULL;
}
bool TestLayer::init()
{
if (CCLayer::init()) {
// if I call setTouchEnabled(true), the destructor does not get called
// if I remove this call, everything works fine
this->setTouchEnabled(true);
return true;
}
return false;
}
void TestLayer::onExit()
{
CCLOG("TestLayer::onExit() called");
// explicitly calling setTouchEnabled(false) does not help
// this->setTouchEnabled(false);
CCLayer::onExit();
}
CCScene* HelloWorld::scene()
{
// 'scene' is an autorelease object
CCScene *scene = CCScene::create();
// 'layer' is an autorelease object
HelloWorld *layer = HelloWorld::create();
// add layer as a child to scene
scene->addChild(layer);
// return the scene
return scene;
}
// using the HelloWorld sample
bool HelloWorld::init()
{
//////////////////////////////
// 1. super init first
if ( !CCLayer::init() )
{
return false;
}
// Init the app.
AppInfo::sharedAppInfo()->initApp();
// ask director the window size
CCSize size = CCDirector::sharedDirector()->getWinSize();
/////////////////////////////
// 2. add a menu item with "X" image, which is clicked to quit the program
// you may modify it.
// add a "close" icon to exit the progress. it's an autorelease object
CCMenuItemImage *pCloseItem = CCMenuItemImage::create(
"CloseNormal.png",
"CloseSelected.png",
this,
menu_selector(HelloWorld::menuCloseCallback) );
pCloseItem->setPosition( ccp(CCDirector::sharedDirector()->getWinSize().width - 20, 20) );
// create menu, it's an autorelease object
CCMenu* pMenu = CCMenu::create(pCloseItem, NULL);
pMenu->setPosition( CCPointZero );
this->addChild(pMenu, 1);
/////////////////////////////
// 3. add your codes below...
// create a test layer to demonstrate the touch issue
TestLayer* testLayer = TestLayer::create();
this->addChild(testLayer);
return true;
}
void HelloWorld::menuCloseCallback(CCObject* pSender)
{
// remove all the children to demonstrate the touch issue
this->removeAllChildrenWithCleanup(true);
CCDirector::sharedDirector()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
exit(0);
#endif
}
I have the same issue, one of my games break after a time when the game is restarted about 5-7 times via replaceScene.
I think this can be the problem of my game too. (I have no idea what can be happenning if this is not the problem)
You can check the source in 2.0.3 , if you setTouchEnabled(true) in init() method ,it will excute registerWithTouchDispatcher to addStandardDelegate and then onEnter method , it will excute registerWithTouchDispatcher too , so it’s a bug here , but not in 2.0.4.