Cocos2d-x 2 0 4 小心隐藏的retain

                         Cocos2d-x中的CCObject类及其派生类,使用autorelease()方法,将自身交托于CCPoolManager管理器进行管理,都可以使用retain()方法来使自身的引用计数加一,使用release()方法来使自身的引用计数减一,当引用计数为0的时候,CCPoolManager管理器就会将其删除释放。

所有实例化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);
     //……
};
若是需要create()方法带有参数的话,仿造CREATE_FUNC的定义来实现, CREATE_FUNC宏定义如下:
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);
     //……
};
其中dPadWithFile静态方法就是仿造的create()方法,具体实现如下:
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开头方便统一。
变量
当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);
};
GameLayer.cpp
1
2
3
4
5
6
7
8
9
10
11
GameLayer::GameLayer( void)
{
     //……
    _robots =  NULL;
}

GameLayer::~GameLayer( void)
{
     //……
    CC_SAFE_RELEASE_NULL(_robots);
}
但是有一种特殊情况,类与变量的互相retain(),导致无法释放,内存泄露。
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);
};
Hero.cpp
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;
}   
_attackAction变量以CCSequence类创建,CCSequence创建包含CCCallFunc的创建, CCCallFunc创建的时候将this指针传递下去,跟踪源码:
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;
}
可以看到它对this指针的对象进行retain()调用,导致Hero对象无法被自动释放,需要先手动对_attackAction变量进行release()调用,CCCallFunc将进行析构,进而将会对this指针的对象进行release()调用
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();
};  
ActionSprite.cpp
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();
}   
最后用Visual Leak Detector和DevPartner检测,均未检测到内存泄露。

如文章存在错误之处,欢迎指出,以便改正。By 无幻           

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值