Cocos2d-x 2.0.4 小心隱藏的retain
阿新 • • 發佈:2018-12-05
Cocos2d-x中的CCObject類及其派生類,使用autorelease()方法,將自身交託於CCPoolManager管理器進行管理,都可以使用retain()方法來使自身的引用計數加一,使用release()方法來使自身的引用計數減一,當引用計數為0的時候,CCPoolManager管理器就會將其刪除釋放。
類
所有例項化Cocos2d-x裡面的以CCObject為基類的類時,都要使用其create()方法來建立物件,對於自己新增的派生類,需要通過 CREATE_FUNC 巨集來實現create()方法,下面以《 如何製作一個橫版格鬥過關遊戲 Cocos2d-x 2.0.4
》來舉例介紹:
Hero.h
若是需要create()方法帶有引數的話,仿造CREATE_FUNC的定義來實現,
CREATE_FUNC
巨集定義如下:
具體可以類似如下:
SimpleDPad.h
其中dPadWithFile靜態方法就是仿造的create()方法,具體實現如下:
當然這裡的方法名可以改為以create開頭方便統一。
變數
當create出來的變數,被 addChild 到以CCNode為基類的類時,或者被 addObject 到CCArray、CCSet等時,都會自動將這個變數物件retain()一次,以防止被自動釋放導致的野指標問題,所以一般情況都不需要再手動呼叫retain()方法了。對於類定義中用 CC_SYNTHESIZE_RETAIN 巨集宣告的變數,或者對臨時變數手動呼叫了retain()方法,一般都需要在解構函式或者特定的函式進行手動呼叫release()方法,類似如下:
GameLayer.h
GameLayer.cpp
但是有一種特殊情況,類與變數的互相retain(),導致無法釋放,記憶體洩露。
ActionSprite.h
Hero.cpp
_attackAction變數以CCSequence類建立,CCSequence建立包含CCCallFunc的建立,
CCCallFunc
建立的時候將this指標傳遞下去,跟蹤原始碼:
可以看到它對this指標的物件進行retain()呼叫,導致Hero物件無法被自動釋放,需要先手動對_attackAction變數進行release()呼叫,CCCallFunc將進行析構,進而將會對this指標的物件進行release()呼叫
解決方法舉例如下:
ActionSprite.h
ActionSprite.cpp
最後用Visual Leak Detector和DevPartner檢測,均未檢測到記憶體洩露。
如文章存在錯誤之處,歡迎指出,以便改正。By 無幻
類
所有例項化Cocos2d-x裡面的以CCObject為基類的類時,都要使用其create()方法來建立物件,對於自己新增的派生類,需要通過 CREATE_FUNC 巨集來實現create()方法,下面以《 如何製作一個橫版格鬥過關遊戲 Cocos2d-x 2.0.4
Hero.h
1
2 3 4 5 6 7 8 9 |
class Hero :
public ActionSprite
{ public: Hero( void ~Hero( void); CREATE_FUNC(Hero); //…… }; |
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#define CREATE_FUNC(__TYPE__) \
static __TYPE__* create() \ { \ __TYPE__ *pRet = new __TYPE__(); \ if (pRet && pRet->init()) \ { \ pRet->autorelease(); \ return pRet; \ } \ else \ { \ delete pRet; \ pRet = NULL; \ return NULL; \ } \ } |
SimpleDPad.h
1
2 3 4 5 6 7 8 9 10 |
class SimpleDPad :
public cocos2d::CCSprite,
public cocos2d::CCTargetedTouchDelegate
{ public: SimpleDPad( void); ~SimpleDPad( void); static SimpleDPad* dPadWithFile(cocos2d::CCString *fileName, float radius); bool initWithFile(cocos2d::CCString *filename, float radius); //…… }; |
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
SimpleDPad* SimpleDPad::dPadWithFile(CCString *fileName,
float radius)
{ SimpleDPad *pRet = new SimpleDPad(); if (pRet && pRet->initWithFile(fileName, radius)) { pRet->autorelease(); return pRet; } else { delete pRet; pRet = NULL; return NULL; } } |
變數
當create出來的變數,被 addChild 到以CCNode為基類的類時,或者被 addObject 到CCArray、CCSet等時,都會自動將這個變數物件retain()一次,以防止被自動釋放導致的野指標問題,所以一般情況都不需要再手動呼叫retain()方法了。對於類定義中用 CC_SYNTHESIZE_RETAIN 巨集宣告的變數,或者對臨時變數手動呼叫了retain()方法,一般都需要在解構函式或者特定的函式進行手動呼叫release()方法,類似如下:
GameLayer.h
1
2 3 4 5 6 7 8 9 10 |
class GameLayer :
public cocos2d::CCLayer,
public SimpleDPadDelegate
{ public: GameLayer( void); ~GameLayer( void); CREATE_FUNC(GameLayer); //…… CC_SYNTHESIZE_RETAIN(cocos2d::CCArray*, _robots, Robots); }; |
1
2 3 4 5 6 7 8 9 10 11 |
GameLayer::GameLayer(
void)
{ //…… _robots = NULL; } GameLayer::~GameLayer( void) { //…… CC_SAFE_RELEASE_NULL(_robots); } |
ActionSprite.h
1
2 3 4 5 6 7 8 9 |
class ActionSprite :
public cocos2d::CCSprite
{ public: ActionSprite( void); ~ActionSprite( void); //…… CC_SYNTHESIZE_RETAIN(cocos2d::CCAction*, _attackAction, AttackAction); }; |
1
2 3 4 5 6 7 8 9 10 11 12 13 |
bool Hero::init()
{ bool bRet = false; do { //…… this->setAttackAction(CCSequence::create(CCAnimate::create(attackAnimation), CCCallFunc::create( this, callfunc_selector(Hero::idle)), NULL)); //…… } while ( 0); return bRet; } |
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
CCCallFunc * CCCallFunc::create(CCObject* pSelectorTarget, SEL_CallFunc selector)
{ CCCallFunc *pRet = new CCCallFunc(); if (pRet && pRet->initWithTarget(pSelectorTarget)) { pRet->m_pCallFunc = selector; pRet->autorelease(); return pRet; } CC_SAFE_DELETE(pRet); return NULL; } bool CCCallFunc::initWithTarget(CCObject* pSelectorTarget) { if (pSelectorTarget) { pSelectorTarget->retain(); } if (m_pSelectorTarget) { m_pSelectorTarget->release(); } m_pSelectorTarget = pSelectorTarget; return true; } |
1
2 3 4 |
virtual ~CCCallFunc()
{ CC_SAFE_RELEASE(m_pSelectorTarget); } |
ActionSprite.h
1
2 3 4 5 6 |
class ActionSprite :
public cocos2d::CCSprite
{ public: //…… virtual void cleanup(); }; |
1
2 3 4 5 6 7 8 |
void ActionSprite::cleanup()
{ CC_SAFE_RELEASE_NULL(_idleAction); CC_SAFE_RELEASE_NULL(_attackAction); CC_SAFE_RELEASE_NULL(_walkAction); CC_SAFE_RELEASE_NULL(_hurtAction); CC_SAFE_RELEASE_NULL(_knockedOutAction); CCSprite::cleanup(); } |
如文章存在錯誤之處,歡迎指出,以便改正。By 無幻