cocos2dx-3.0(32) retain和release

~~~~我的生活,我的点点滴滴!!


这篇文章是从木头那里顺手拿过来的,木头即手游戏版主,牛逼闪闪的人物,刚好我写程序的时候遇到这成员变量莫名其妙的成野指针问题,他讲的很好,我也懒得在组织语言了!


1、为什么会有retain?

C++和Java不一样,Java有一套很方便的垃圾回收机制,当我们不需要使用某个对象时,给它赋予null值即可。

而C++new了一个对象之后,不使用的时候通常需要delete掉。于是,Cocos2d-x

就发明了一套内存管理机制,红孩儿的博客很详细地解释了Cocos2d-x的内存管理机制。retain的意思是保持引用,

也就是说,如果想保持某个对象的引用,避免它被Cocos2d-x释放,那就是调用对象的retain函数。

 
 

2、真正的凶手autoRelease

一旦调用对象的autoRelease函数,那么这个对象就被Cocos2d-x的内存管理机制给盯上了,如果这个对象没人认领,那就等着被释放吧。
 

3、看代码实际点

bool HelloWorld::init()  
{  
    bool bRet = false;  
	
	......
  
    testSprite = CCSprite::create("HelloWorld.png");  

    return bRet;  
}  

testSprite是一个成员变量,在头文件里加上就可以了:

class HelloWorld : public cocos2d::CCLayer  
{  
public:  
    virtual bool init();    
    static cocos2d::CCScene* scene();  
    void menuCloseCallback(CCObject* pSender);  
    CREATE_FUNC(HelloWorld);  
private:  
    cocos2d::CCSprite* testSprite;  
};  

然后,最关键的来了,我们修改menuCloseCallback函数:

void HelloWorld::menuCloseCallback(CCObject* pSender)  
{  
    testSprite->getPosition();  
}  

现在,运行项目,点击按钮,看看是什么情况?

是的 报错 直接崩溃!!!!!!!!!!

我们调试会testSprite对象被释放了,现在testSprite指向未知的位置,但是我们确实在程序中没有释放他,这太奇怪了!!!!
 
要想解决这个问题,很简单,再次修改init函数:

bool HelloWorld::init()  
{  

	......
	
    testSprite = CCSprite::create("HelloWorld.png");
	
  testSprite->retain();  

    return bRet;  
}  

再次运行项目,看看还会不会报错? 不会了!!!!!

再次用调试模式运行项目,发现testSprite对象正常了。


4、原理

首先,要想让对象参与内存管理机制,必须继承Ref类。

然后,调用对象的autoRelease函数,对象就会被Cocos2d-x的内存管理机制盯上,在游戏的每一帧,内存管理机制都会扫描一遍被盯上的对象,一旦发现对象无人认领,就会将对象杀死!

如果不想让对象被杀死,那么就要调用对象的retain函数,这样对象就被认领了,一旦对象被认领,就永远不会被内存管理机制杀掉,是永远,一辈子。

但是,对象一辈子都不被释放的话,那么就会产生内存泄露,你试试加载一个占20M内存的对象一辈子不释放,不折腾死才怪~因此,当你不需要再使用这个对象时,就要调用对象的release

函数,这是和retain对应的。一般可以在析构函数里调用release函数。

 
 

5、实际情况

讲道理,大家都懂,但是,相信很多朋友在实际写代码的时候,还是会感觉很混乱。

比如,什么时候该retain?大家是不是发现,有时候不retain也不会报错?

其实这很简单,因为我们经常会在create一个对象之后,添加到层里,如:

testSprite = CCSprite::create("HelloWorld.png");

this->addChild(testSprite);

addChild函数就是导致大家混乱的凶手了,addChild函数会调用对象的retain函数,为什么它要调用对象的retain函数呢?因为你都把对象送给它当孩子了,

它当然要认领这个对象了!于是,当我们把对象addChild到Layer时(不一定是Layer,Array、Node都行),我们就不需要调用对象的retain函数了。

 
 

6、倒底什么时候要retain?

说了这么多,还是没有说清楚,什么时候要调用对象的retain。

很简单,当你把一个对象作为成员变量时,并且没有把对象addChild到另外一个对象时,就需要调用retain函数。
 

7、切记

一定要记住,必须要调用了对象的autoRelease函数之后,retain和release函数才会生效,否则,一切都是徒劳。

因此,十分建议使用create的方式创建对象,如:

CCSprite* CCSprite::create(const char *pszFileName)  
{  
    CCSprite *pobSprite = new CCSprite();  
    if (pobSprite && pobSprite->initWithFile(pszFileName))  
    {  
        pobSprite->autorelease();  
        return pobSprite;  
    }  
    CC_SAFE_DELETE(pobSprite);  
    return NULL;  
}  

retain源码级别的解说,请到红孩儿的博客!!那是真正的大神。


红海儿传送门 点击打开链接


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值