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

来源:互联网 发布:数控编程仿真软件 编辑:程序博客网 时间:2024/05/17 06:54

我们知道,我们在新建一个节点类的时候,一般会在这个类里面添加一个宏,那就是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;

SceneStoryScene::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(), such as Layer

 */

#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是将对象加入到自动释放池,那这样做的作用是什么,有什么好处吗?

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

SceneMenuScene::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方法释放对象,此时layer的引用计1-1=0,此时对象被释放从上面我们可以知道,对象的autorelease方法是针对于new的,该方法使我们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 localZOrder, int tag, const std::string &name, boolsetTag)

{

    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的自动内存管理机制。


阅读全文
0 0