Cocos2d-x内存管理之autorelease,addChild和removeFromParent

前端之家收集整理的这篇文章主要介绍了Cocos2d-x内存管理之autorelease,addChild和removeFromParent前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

我们知道,我们在新建一个节点类的时候,一般会在这个类里面添加一个宏,那就是CREATE_FUNC这样的一个宏,

如下:

#ifndef __HELLOWORLD_SCENE_H__

#define __HELLOWORLD_SCENE_H__


#include "cocos2d.h"

using namespace cocos2d;


class StoryScene : public cocos2d::Layer

{

public:

static cocos2d::Scene* createScene();

virtual bool init();

CREATE_FUNC(StoryScene);

private:

void menuCallBack();

};


#endif


有些人在添加了这个宏之后,使用这个类去创建对象的时候,会发现这个类有一个create方法,可以创建这个类的对象,并且会自动调用类的init方法去初始化对象,如下:

#include "StoryScene.h"

USING_NS_CC;

Scene* StoryScene::createScene()

{

// 'scene' is an autorelease object

auto scene = Scene::create();

// 'layer' is an autorelease object

auto layer = StoryScene::create();


// add layer as a child to scene

scene->addChild(layer);


// return the scene

return scene;

}


// on "init" you need to initialize your instance

bool StoryScene::init()

{

//////////////////////////////

// 1. super init first

if ( !Layer::init() )

{

return false;

}

return true;

}

其实,这个create方法就是CREATE_FUNC宏帮我们创建的,我们看一下CREATE_FUNC做了什么

/**

* define a create function for a specific type,such as Layer

* @param \__TYPE__ class type to add create(),255)">*/

#define CREATE_FUNC(__TYPE__) \

定义一个静态方法create,返回传入的类的指针

static __TYPE__* create() \

{ \

通过new创建改类的对象

__TYPE__ *pRet = new(std::nothrow) __TYPE__(); \

如果创建成功并且调用init方法初始化成功

if (pRet && pRet->init()) \

{ \

将对象加入到自动释放池中

pRet->autorelease(); \

返回该对象

return pRet; \

} \

否则,创建对象失败

else \

{ \

释放对象

delete pRet; \

将对象置空

pRet = NULL; \

返回NULL

return NULL; \

} \

}

其中的autorelease是将对象加入到自动释放池,那这样做的作用是什么,有什么好处吗?

我们以下面的例子为例来将它的作用:

Scene* MenuScene::createScene(int openLevels)

{

auto scene=Scene::create();

//new之后对象的引用计数为1

auto layer=new MenuScene();

if(layer&&layer->init(openLevels))

{

//把对象加入到自动释放池里面,1帧之后对象的引用计数将会减1,引用计数为0的时候对象会被释放

layer->autorelease();

/*layer添加到其父节点scene上,layeraddChild方法内部会被retain一次,所以此时layer的引用计数为2当一帧过后,layer引用计数将会减1,则1帧后layer的引用计数为2-1=1,当layer被移除父节点的时候,也就是调用layer->removeFromParent()方法的时候,方法内部会调用layerrelease方法释放对象,此时的引用计1-1=0,此时对象被释放从上面我们可以知道,对象的autorelease方法是针对于new的,该方法使我们出对象之后不需要我们手动的去调用对象release方法去释放对象,减少了内存泄露的几率 用这种方法创建出来的对象,如果没有立即加到父节点中,那么一帧过后使用对象的时候,就会出现空指针异常,因为此时对象已经被释放了*/

scene->addChild(layer);

}else{

CC_SAFE_DELETE(layer);

layer=NULL;

}

return scene;

}

下面是addChild和removeFromParent的底层代码

void Node::addChild(Node* child,int localZOrder,const std::string &name)

{

CCASSERT(child != nullptr,"Argument must be non-nil");

CCASSERT(child->_parent == nullptr,"child already added. It can't be added again");

addChildHelper(child,localZOrder,INVALID_TAG,name,false);

}

child作为addChildHelper的参数传递了进入,我们跟进addChildHelper看看:

void Node::addChildHelper(Node* child,int tag, const std::string &name, bool setTag)

{

if (_children.empty())

{

this->childrenAlloc();

}

this->insertChild(child,localZOrder);

if (setTag)

child->setTag(tag);

else

child->setName(name);

child->setParent(this);

child->setOrderOfArrival(s_globalOrderOfArrival++);

#if CC_USE_PHYSICS

// Recursive add children with which have physics body.

auto scene = this->getScene();

if (scene && scene->getPhysicsWorld())

{

scene->addChildToPhysicsWorld(child);

}

#endif

if( _running )

{

child->onEnter();

// prevent onEnterTransitionDidFinish to be called twice when a node is added in onEnter

if (_isTransitionFinished)

{

child->onEnterTransitionDidFinish();

}

}

if (_cascadeColorEnabled)

{

updateCascadeColor();

}

if (_cascadeOpacityEnabled)

{

updateCascadeOpacity();

}

}

我们再跟进insertChild

void Node::insertChild(Node* child,int z)

{

_transformUpdated = true;

_reorderChildDirty = true;

_children.pushBack(child);

child->_localZOrder = z;

}

再跟进pushBack

void pushBack(T object)

{

CCASSERT(object != nullptr,"The object should not be nullptr");

_data.push_back( object );

object->retain();

}

我们可以看到,对象被retain了

同理跟进removeFromParent的源代码,我们也会发现对象被release了。

这就是cocos的自动内存管理机制。

猜你在找的Cocos2d-x相关文章