我們知道,我們在建立一個節點類的時候,一般會在這個類裡面添加一個宏,那就是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 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();
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 localZOrder, 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的自動記憶體管理機制。