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上,layer在addChild方法内部会被retain一次,所以此时layer的引用计数为2当一帧过后,layer引用计数将会减1,则1帧后layer的引用计数为2-1=1,当layer被移除父节点的时候,也就是调用layer->removeFromParent()方法的时候,方法内部会调用layer的release方法释放对象,此时的引用计为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(); } } 我们再跟进insertChildvoid 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的自动内存管理机制。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |