Cocos2d-x 2.0.4 小心隐藏的retain
2013-07-29 14:13
190 查看
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 无幻
相关文章推荐
- Cocos2d-x 2.0.4 小心隐藏的retain
- Cocos2d-x2.0.4 CCBReader readFloat 隐藏BUG
- Cocos2d-X开发中国象棋《十二》游戏结果的显示与隐藏
- [cocos2d-x 2.0.4][iOS7]不能全屏问题
- 如何制作一个塔防游戏 Cocos2d-x 2.0.4
- cocos2d-2.0-x-2.0.4生成vs2010项目模板的解决方法
- cocos2d-x内存管理retain和release
- Cocos2d-x 内存管理中retain() 、autoRelease()、release()
- 如何制作一个横版格斗过关游戏 Cocos2d-x 2.0.4
- 如何制作飞镖忍者(2) Cocos2d-x 2.0.4
- Cocos2d-x 2.0.4 如何制作一个简单的游戏(3)
- 如何制作一个基于Tile的游戏(2) Cocos2d-x 2.0.4
- 构建cocos2d-x 的android项目(cocos2d-2.0-x-2.0.4)
- android下,cocos2d-x输入框隐藏问题。
- [cocos2d-x 2.0.4][iOS7]图片加载错误
- [cocos2d-x 2.0.4][iOS7]不能全屏问题
- cocos2d隐藏按钮
- cocos2d-x 文本设置隐藏无效
- cocos2d-x 2.0 小心CCNode::setVisible,一不小心就看不见了
- cocos2d x 入门学习(三)如何制作一个塔防游戏 Cocos2d-x 2.0.4