接上一节内容: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时,释放对象。

  1. void Ref::retain()
  2. {
  3. CCASSERT(_referenceCount > , "reference count should be greater than 0");
  4. ++_referenceCount;
  5. }
  6.  
  7. void Ref::release()
  8. {
  9. CCASSERT(_referenceCount > , "reference count should be greater than 0");
  10. --_referenceCount;
  11.  
  12. if (_referenceCount == )
  13. {
  14. delete this;
  15. }
  16. }

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

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

  1. // Adds objects
  2.  
  3. /** Adds a new element at the end of the Vector. */
  4. void pushBack(T object)
  5. {
  6. CCASSERT(object != nullptr, "The object should not be nullptr");
  7. _data.push_back( object );
  8. object->retain();
  9. }
  10. /** @brief Removes from the vector with an iterator.
  11. * @param position Iterator pointing to a single element to be removed from the Vector.
  12. * @return An iterator pointing to the new location of the element that followed the last element erased by the function call.
  13. * This is the container end if the operation erased the last element in the sequence.
  14. */
  15. iterator erase(iterator position)
  16. {
  17. CCASSERT(position >= _data.begin() && position < _data.end(), "Invalid position!");
  18. (*position)->release();
  19. return _data.erase(position);
  20. }

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

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

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

  1. Ref::Ref()
  2. : _referenceCount() // when the Ref is created, the reference count of it is 1
  3. {
  4. #if CC_ENABLE_SCRIPT_BINDING
  5. static unsigned int uObjectCount = ;
  6. _luaID = ;
  7. _ID = ++uObjectCount;
  8. _scriptObject = nullptr;
  9. #endif
  10.  
  11. #if CC_REF_LEAK_DETECTION
  12. trackRef(this);
  13. #endif
  14. }

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

  1. /** @def CREATE_FUNC(__TYPE__)
  2. * Define a create function for a specific type, such as Layer.
  3. *
  4. * @param __TYPE__ class type to add create(), such as Layer.
  5. */
  6. #define CREATE_FUNC(__TYPE__) \
  7. static __TYPE__* create() \
  8. { \
  9. __TYPE__ *pRet = new(std::nothrow) __TYPE__(); \
  10. if (pRet && pRet->init()) \
  11. { \
  12. pRet->autorelease(); \
  13. return pRet; \
  14. } \
  15. else \
  16. { \
  17. delete pRet; \
  18. pRet = nullptr; \
  19. return nullptr; \
  20. } \
  21. }

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

  1. Ref* Ref::autorelease()
  2. {
  3. PoolManager::getInstance()->getCurrentPool()->addObject(this);
  4. return this;
  5. }

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

  1. void DisplayLinkDirector::mainLoop()
  2. {
  3. if (_purgeDirectorInNextLoop)
  4. {
  5. _purgeDirectorInNextLoop = false;
  6. purgeDirector();
  7. }
  8. else if (_restartDirectorInNextLoop)
  9. {
  10. _restartDirectorInNextLoop = false;
  11. restartDirector();
  12. }
  13. else if (! _invalid)
  14. {
  15. drawScene();
  16.  
  17. // release the objects
  18. PoolManager::getInstance()->getCurrentPool()->clear();
  19. }
  20. }
  1. void AutoreleasePool::clear()
  2. {
  3. #if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
  4. _isClearing = true;
  5. #endif
  6. std::vector<Ref*> releasings;
  7. releasings.swap(_managedObjectArray);
  8. for (const auto &obj : releasings)
  9. {
  10. obj->release();
  11. }
  12. #if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
  13. _isClearing = false;
  14. #endif
  15. }

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

几个示例:

  1. Scene* pScene = Director::getInstance()->getRunningScene();
  2. if (pScene)
  3. {
  4. Node* pNode1 =Node::create(); // pNode1创建后没有处理,在当前帧结束前被释放
  5.  
  6. Node* pNode2 =Node::create(); // pNode2创建后添加到场景中,不会被释放
  7. pScene->addChild(pNode2);
  8.  
  9. Node* pNode3 =pScene->getChildByTag();
  10. if(pNode3)
  11. {
  12. pScene->removeChild(pNode3); // pNode3被立即释放
  13. pNode2->addChild(pNode3); // 错误!! pNode3已被释放
  14. }
  15.  
  16. Node* pNode4 =Node::create();
  17. pNode2->addChild(pNode4); // pNode4 随 pNode2释放
  18.  
  19. Node* pNode5 =Node::create();
  20. pScene->addChild(pNode5);
  21. pNode5->retain();
  22. pScene->removeChild(pNode5);
  23. pNode2->addChild(pNode5);
  24. pNode5->release(); // pNode5 随 pNode2释放
  25.  
  26. }

cocos2dx - 节点管理的更多相关文章

  1. 2、COCOS2D-X内存管理机制

    在C++中.动态内存分配是一把双刃剑,一方面,直接訪问内存地址提高了应用程序的性能,与使用内存的灵活性.还有一方面.因为程序没有正确地分配与释放造成的比如野指针,反复释放,内存泄漏等问题又严重影响着应 ...

  2. cocos2d-x内存管理

    Cocos2d-x内存管理 老师让我给班上同学讲讲cocos2d-x的内存管理,时间也不多,于是看了看源码,写了个提纲和大概思想 一.   为什么需要内存管理 1. new和delete 2. 堆上申 ...

  3. 在控制台启动服务器时出现:对于服务器soa1_wls, 与计算机oim1相关联的节点管理器无法访问。

    问题:在控制台启动服务器时出现:对于服务器soa1_wls, 与计算机oim1相关联的节点管理器无法访问.原因:nodemanager没有启起来解决方法: 一.对于managedServer于admi ...

  4. [转] Jenkins实战演练之Windows系统节点管理

    [前提] 通过<Jenkins实战演练之Windows服务器快速搭建>(http://my.oschina.net/iware/blog /191818)和<Jenkins实战演练之 ...

  5. 转:对于服务器AdminServer, 与计算机Machine-0相关联的节点管理器无法访问

    控制台启动server时报"对于服务器server-1与计算机machin<!--StartFragment -->对于服务器AdminServer, 与计算机Machine-0 ...

  6. 20151208_使用windows2012配置weblogic节点管理器

    经过实践,weblogic节点管理器的作用主要有两点: 1.可通过weblogic控制台远程控制被管server启停. 2.可以自动重启被管server的进程,并且对spring框架提供比直接启动更快 ...

  7. weblogic11g 节点管理器 nodemanager

    Weblogic 节点管理器  nodemanager 一.Weblogic  规划 : Server名称 端口 ip 备注 xyyadmin 7001 10.10.54.74 管理server ap ...

  8. cocos2dx内存管理的一些看法

    今年年初进入一家游戏公司,正式开始游戏引擎的学习,之前的ios学习,对现在的游戏引擎学习还是有很大的帮助的,虽然使用c++,但却能时刻感受到ios框架对于cocos2dx的巨大影响. 由于之前一直使用 ...

  9. Cocos2d-x内存管理解说在ios开发中

    使用过 Cocos2d-x 都知道,其中有一套自己实现的内存管理机制,不同于一般 C++ 的编写常规,而在使用前,了解其原理是有必要的,网上已经有很多对内部实现详细解说的文章.而对于使用者而言,并不需 ...

随机推荐

  1. 软工+C(2017第6期) 最近发展区/脚手架

    // 上一篇:工具和结构化 // 下一篇:野生程序员 教育心理学里面有提到"最近发展区"这个概念,这个概念是前苏联发展心理学家维果茨基(Vygotsky)提出的,英文名词是Zone ...

  2. 四则运算GUI版

    小学四则运算界面版 李永豪 201421123117 郑靖涛 201421123114 coding 地址:https://git.coding.net/ras/work2.git 一.题目描述 我们 ...

  3. 1001.A+B Format (20)代码自查(补足版)

    1001.A+B Format (20)代码自查(补足版) 谢谢畅畅酱的提醒,发现了代码中的不足,把变量名更改成更合理的名字,并且把注释也换成英文啦! 栋哥提供的代码自查的方式也帮助了我发现很多代码中 ...

  4. 软件工程资料 - UCSD 怎么教软件工程

    2012年,在上软件工程课的过程中,收集到这个博客,作为学习资料. 原网站 (http://www.arc-trooper.com)已经不存在,这是一个备份. ----------------- 以下 ...

  5. 团队作业4——第一次项目冲刺(Alpha版本)2017.4.25

    在下午的1,2节软件课程结束后,我们teamworkers全体队员在禹州楼302利用课间时间进行约15分钟的短暂会议,会议的内容为阐述昨天开发遇到的问题,大家都提出自己的看法,最后统一了意见,队员互相 ...

  6. 【Alpha】Daily Scrum Meeting——Day3

    站立式会议照片 1.本次会议为第三次 Meeting会议: 2.本次会议于早上9:40在陆大楼召开,本次会议为30分钟讨论昨天的任务完成情况以及接下来的任务安排. 每个人的工作分配 成 员 昨天已完成 ...

  7. 201521123102 《Java程序设计》第3周学习总结

    1. 本周学习总结 初学面向对象,会学习到很多碎片化的概念与知识.尝试学会使用思维导图将这些碎片化的概念.知识组织起来.请使用纸笔或者下面的工具画出本周学习到的知识点.截图或者拍照上传. 2. 书面作 ...

  8. 201521123093 java 第九周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常相关内容. 2. 书面作业 本次PTA作业题集异常 1.常用异常 题目5-1 1.1 截图你的提交结果(出现学号) 1.2 自己 ...

  9. 多线程面试题系列(7):经典线程同步 互斥量Mutex

    前面介绍了关键段CS.事件Event在经典线程同步问题中的使用.本篇介绍用互斥量Mutex来解决这个问题. 互斥量也是一个内核对象,它用来确保一个线程独占一个资源的访问.互斥量与关键段的行为非常相似, ...

  10. Python爬虫1-----------placekitten 入门

    常用的urllib库有三个类:request,parse,error,request主要完成对url的请求,如proxy,opener,urlopen,parse主要完成对html的解析,error负 ...