其实这个原理和上边的例子是差不多的,我们创建了一个CCArray的对象,这个时候同样是没有添加到其他的层中的,所以在这一帧结束的时候就会将它的引用计数减1变成0,所以,再次使用的时候肯定就会出错了!在使用cocos2dx的内存管理的时候如果我们是通过工厂的方法创建的,并且add到了其他的层中的时候这个时候我们多数是不用担心的,但是如果你是通过new的方法创建的CCObject子类的对象,这个时候记住要在析构的时候release这个对象,如果在使用过程中你retain了对象,同样记住要release。本人总结的是,当我们调用函数传递CCObject子类对象的时候,在接受的时候我们都应该去retain一下,这样代表的是我要引用这块内存空间,什么时候你不再引用这块内存空间了,就release一下。其他的各种问题当你遇到的时候就想一下它的原理,就会明白的。最后的最后欢迎广大网友给我留言,我们共同探讨cocos2dx的问题!
以下是自己看代码的:
main函数中有这样一句:return Application::getInstance()->run();直接跳到这部分代码看下,while循环下有一句:director->mainLoop();
void DisplayLinkDirector::mainLoop()
{
if (_purgeDirectorInNextLoop)
{
_purgeDirectorInNextLoop = false;
purgeDirector();
}
else if (! _invalid)
{
drawScene();
// release the objects
PoolManager::getInstance()->getCurrentPool()->clear();
}
} 可以看到,如果当前场景有效的话,调用了两句,这里看
PoolManager::getInstance()->getCurrentPool()->clear(),跳转到clear函数:
void AutoreleasePool::clear()
{
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
_isClearing = true;
#endif
for (const auto &obj : _managedObjectArray)
{
obj->release();
}
_managedObjectArray.clear();
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
_isClearing = false;
#endif
} 可以看到,在mainLoop函数中,也就是每一帧中,每次都对回收池中的对象进行了release操作,并且把当前的内存池清空,再看release都做了什么:
void Ref::release()
{
CCASSERT(_referenceCount > 0,"reference count should greater than 0");
--_referenceCount;
if (_referenceCount == 0)
{
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
auto poolManager = PoolManager::getInstance();
if (!poolManager->getCurrentPool()->isClearing() && poolManager->isObjectInPools(this))
{
// Trigger an assert if the reference count is 0 but the Ref is still in autorelease pool.
// This happens when 'autorelease/release' were not used in pairs with 'new/retain'.
//
// Wrong usage (1):
//
// auto obj = Node::create(); // Ref = 1,but it's an autorelease Ref which means it was in the autorelease pool.
// obj->autorelease(); // Wrong: If you wish to invoke autorelease several times,you should retain `obj` first.
//
// Wrong usage (2):
//
// auto obj = Node::create();
// obj->release(); // Wrong: obj is an autorelease Ref,it will be released when clearing current pool.
//
// Correct usage (1):
//
// auto obj = Node::create();
// |- new Node(); // `new` is the pair of the `autorelease` of next line
// |- autorelease(); // The pair of `new Node`.
//
// obj->retain();
// obj->autorelease(); // This `autorelease` is the pair of `retain` of previous line.
//
// Correct usage (2):
//
// auto obj = Node::create();
// obj->retain();
// obj->release(); // This `release` is the pair of `retain` of previous line.
CCASSERT(false,"The reference shouldn't be 0 because it is still in autorelease pool.");
}
#endif
delete this;
}
} 对引用计数值减1,当为0的时候,直接从内存中删除。
下面拿sprite来看下:
Sprite* Sprite::create(const std::string& filename)
{
Sprite *sprite = new Sprite(); //引用计数为1
if (sprite && sprite->initWithFile(filename))
{
sprite->autorelease();//并且交给回收池管理
return sprite;
}
CC_SAFE_DELETE(sprite);
return nullptr;
} 当进行addchild操作时,有一句this->insertChild(child,zOrder);,跟进去:
void Node::insertChild(Node* child,int z) { _reorderChildDirty = true; _children.pushBack(child); child->_setLocalZOrder(z); }
再看pushBack,
void pushBack(T object)
{
CCASSERT(object != nullptr,"The object should not be nullptr");
_data.push_back( object );
object->retain();
} 这里又retain了一次,引用计数为2了。在上面一帧结束的时候release就变成了1.这时只有他的parent对他拥有引用计数1.当parent析构时,
void Node::removeFromParentAndCleanup(bool cleanup)
{
if (_parent != nullptr)
{
_parent->removeChild(this,cleanup);
}
}
void Node::removeChild(Node* child,bool cleanup /* = true */)
{
// explicit nil handling
if (_children.empty())
{
return;
}
ssize_t index = _children.getIndex(child);
if( index != CC_INVALID_INDEX )
this->detachChild( child,index,cleanup );
}
void Node::detachChild(Node *child,ssize_t childIndex,bool doCleanup)
{
// IMPORTANT:
// -1st do onExit
// -2nd cleanup
if (_running)
{
child->onExitTransitionDidStart();
child->onExit();
}
#if CC_USE_PHYSICS
if (child->_physicsBody != nullptr)
{
child->_physicsBody->removeFromWorld();
}
#endif
// If you don't do cleanup,the child's actions will not get removed and the
// its scheduledSelectors_ dict will not get released!
if (doCleanup)
{
child->cleanup();
}
// set parent nil at the end
child->setParent(nullptr);
_children.erase(childIndex);
}
iterator erase(ssize_t index)
{
CCASSERT(!_data.empty() && index >=0 && index < size(),"Invalid index!");
auto it = std::next( begin(),index );
(*it)->release();
return _data.erase(it);
} 进行了release操作,这时引用对数为0,最后设置他的父节点为空,并且从父节点子节点数组中删除。 (编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|