zoukankan      html  css  js  c++  java
  • cocos2dx

    接上一节内容:cocos2dx - v2.3.3编辑器骨骼动画

    本节主要Cocos2dx中节点的管理及应用

    一般用法

      用过Cocos2dx应该都有用过addChild,removeChild方法。或者retain,release方法。

    addChild,removeChild方法都是继承Node类,retain,release方法则继承自Ref类。

    查看cocos2dx库代码可以看到,Ref中retain,release主要维持了一个_referenceCount计数变量

    通过retain方法可以使_referenceCount计数加1,同时release可以使_referenceCount计数减1,并且在_referenceCount计数为0时,释放对象。

    void Ref::retain()
    {
        CCASSERT(_referenceCount > 0, "reference count should be greater than 0");
        ++_referenceCount;
    }
    
    void Ref::release()
    {
        CCASSERT(_referenceCount > 0, "reference count should be greater than 0");
        --_referenceCount;
    
        if (_referenceCount == 0)
        {
            delete this;
        }
    }

    查看Node的实现也可以了解Node中维护了一个CCVector对象来存储子节点,在erase子节点时,对子节点调用release方法,同时在pushBack新节点时,对子节点调用retain方法。

    下面是CCVector中pushBack及erase的一些细节:

        // Adds objects
        
        /** Adds a new element at the end of the Vector. */
        void pushBack(T object)
        {
            CCASSERT(object != nullptr, "The object should not be nullptr");
            _data.push_back( object );
            object->retain();
        }
            /** @brief Removes from the vector with an iterator. 
         *  @param position Iterator pointing to a single element to be removed from the Vector.
         *  @return An iterator pointing to the new location of the element that followed the last element erased by the function call.
         *          This is the container end if the operation erased the last element in the sequence.
         */
        iterator erase(iterator position)
        {
            CCASSERT(position >= _data.begin() && position < _data.end(), "Invalid position!");
            (*position)->release();
            return _data.erase(position);
        }
        

    这样就说明了Node节点实际还是在对Ref继承的_referenceCount进行计数处理。

    若Node没有添加到父节点中,那么_referenceCount什么时候变成0,又什么时候释放节点的?

    首先在Ref的构造函数中,可以看到_referenceCount初始化为1

    Ref::Ref()
    : _referenceCount(1) // when the Ref is created, the reference count of it is 1
    {
    #if CC_ENABLE_SCRIPT_BINDING
        static unsigned int uObjectCount = 0;
        _luaID = 0;
        _ID = ++uObjectCount;
        _scriptObject = nullptr;
    #endif
        
    #if CC_REF_LEAK_DETECTION
        trackRef(this);
    #endif
    }

    同时,在Node的静态创建方法Node::create中,宏定义  CREATE_FUNC(Node)  实现如下,

    /** @def CREATE_FUNC(__TYPE__)
     * 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__) 
    static __TYPE__* create() 
    { 
        __TYPE__ *pRet = new(std::nothrow) __TYPE__(); 
        if (pRet && pRet->init()) 
        { 
            pRet->autorelease(); 
            return pRet; 
        } 
        else 
        { 
            delete pRet; 
            pRet = nullptr; 
            return nullptr; 
        } 
    }

    可以看到,在对象创建失败会直接delete,并返回nullptr。创建成功则调用了autorelease方法,如下:

    Ref* Ref::autorelease()
    {
        PoolManager::getInstance()->getCurrentPool()->addObject(this);
        return this;
    }

    说明在正常创建Node节点时,会将其添加到coco2dx的一个内存池进行管理。同时在主循环中看到,下一帧处理对当前内存池对象进行了一次清理,并调用了release方法。

    void DisplayLinkDirector::mainLoop()
    {
        if (_purgeDirectorInNextLoop)
        {
            _purgeDirectorInNextLoop = false;
            purgeDirector();
        }
        else if (_restartDirectorInNextLoop)
        {
            _restartDirectorInNextLoop = false;
            restartDirector();
        }
        else if (! _invalid)
        {
            drawScene();
         
            // release the objects
            PoolManager::getInstance()->getCurrentPool()->clear();
        }
    }
    void AutoreleasePool::clear()
    {
    #if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
        _isClearing = true;
    #endif
        std::vector<Ref*> releasings;
        releasings.swap(_managedObjectArray);
        for (const auto &obj : releasings)
        {
            obj->release();
        }
    #if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
        _isClearing = false;
    #endif
    }

    因此,如果一个对象在创建后,没有及时进行retain或者添加到父节点中,在当前帧结束时被调用release方法导致 _referenceCount变成0,从而被释放。

    几个示例:

    Scene* pScene = Director::getInstance()->getRunningScene();
    if (pScene)
    {
        Node* pNode1 =Node::create();     //  pNode1创建后没有处理,在当前帧结束前被释放
        
        Node* pNode2 =Node::create();    //  pNode2创建后添加到场景中,不会被释放
        pScene->addChild(pNode2);
        
        Node* pNode3 =pScene->getChildByTag(3);
        if(pNode3)
        {
            pScene->removeChild(pNode3);     //  pNode3被立即释放
            pNode2->addChild(pNode3);        // 错误!! pNode3已被释放
        }
        
         
        Node* pNode4 =Node::create();
        pNode2->addChild(pNode4);            //  pNode4 随 pNode2释放
         
        Node* pNode5 =Node::create();
        pScene->addChild(pNode5);
        pNode5->retain();
        pScene->removeChild(pNode5);
        pNode2->addChild(pNode5);
        pNode5->release();                    //  pNode5 随 pNode2释放
        
    }


     

  • 相关阅读:
    使用jquey的css()方法改变样式,
    js 小总结
    .net mvc项目 ajax
    推荐一个优秀的前端框架——Bootstrap
    关于页面优化的方法收集(不断更新)
    软件开发中没有所谓正确的方法(转)
    PHP框架CI(codeigniter)的使用笔记
    前端知识结构图(转)
    PHP生成缩略图的一个方法类(转)
    apache设置映射文件夹的配置方法
  • 原文地址:https://www.cnblogs.com/stratrail/p/5044610.html
Copyright © 2011-2022 走看看