當時被問到CCNode、CCObject、CCScene、CCACtion等是幹什麼用的、有什麼意義時我不知道,只是初略的看過一些而已。
由於我只大致看過一些資料,看了些Test工程而已,這些源碼當時覺得暫時沒必要看,實際的開發中會慢慢接觸到。現在知道我做錯了,如果在使用一個技術之前,不好好了解技術原理,就是非常坑爹的事情!
廢話完了,希望和同學們一起好好分析這個類,達到舉一反三,甚至一勞永逸的效果,如有分析錯誤的地方,希望哪位同學幫我立刻指出來,多謝!
---------------------------------------------------------------------------------------------
編程環境:Visual Studio 2010
Coco版本:cocos2d-x-2.1.4
---------------------------------------------------------------------------------------------
在CCObject.h中定義了兩個類:CCCopying、CCObject。
class CC_DLL CCCopying
{
public:
virtual CCObject* copyWithZone(CCZone* pZone);
};
CC_DLL是一個宏定義,它使得類的輸出爲DLL,定義如下:
#define CC_DLL __declspec(dllexport)
總得來說,它是一個協議形式的類,繼承於它的類都能夠進行復制。
接着回來看CCObject:
class CC_DLL CCObject : public CCCopying
{
public:
// object id, CCScriptSupport need public m_uID
unsigned int m_uID;
// Lua reference id
int m_nLuaID;
protected:
// count of references
unsigned int m_uReference;
// count of autorelease
unsigned int m_uAutoReleaseCount;
public:
CCObject(void);
virtual ~CCObject(void);
void release(void);
void retain(void);
CCObject* autorelease(void);
CCObject* copy(void);
bool isSingleReference(void) const;
unsigned int retainCount(void) const;
virtual bool isEqual(const CCObject* pObject);
virtual void acceptVisitor(CCDataVisitor &visitor);
virtual void update(float dt) {CC_UNUSED_PARAM(dt);};
friend class CCAutoreleasePool;
};
大致看一下,然後我們逐個深入CCObject的方法(函數和方法是同一個東東,以後不再說明^ ^)實現。
不是所有內容都需要分析,就好比方學習C++一樣,C++之父說過“用到哪學到哪”。
CCObject構造函數:
CCObject::CCObject(void)
: m_nLuaID(0)
, m_uReference(1) // when the object is created, the reference count of it is 1
, m_uAutoReleaseCount(0)
{
static unsigned int uObjectCount = 0;
m_uID = ++uObjectCount;
}
上面的構造函數中,主要是設置引用計數的計數器爲1。什麼,不知道引用計數幹嘛用的?它解決了對象被多處地方引用時的管理方法。
在程序的生命週期內,當兩處及兩處以上地方在使用此對象時,你無法判斷內存中的對象何時應該被釋放。如果不使用此對象,則調用對象的release方法,計數器會減1。如果計數器的值爲0,那麼這個對象纔會從內存中,被釋放掉(最後一個地方release時,就會delete對象)。
void CCObject::release(void)
{
CCAssert(m_uReference > 0, "reference count should greater than 0");
--m_uReference;
if (m_uReference == 0)
{
delete this;
}
}
上面的release方法可以看到每次調用此方法時,m_uReference就會減1,直到m_uReference爲0。
既然說到這裏,我們初學C++或Cocos2d-x的同學肯定有個疑惑:怎麼才能再多個地方使用對象?
答:指針傳遞。
指針傳遞之後,就多處地方使用了這個內存對象,那從哪裏增加引用計數的值?(內存對象的說法比對象更貼近實際,以後不解釋;) )
答:這就是retain()方法的由來咯,使用retain方法,m_uReference就會增1。當傳遞對象指針時,首先調用retain()方法,然後再賦值地址。
示例代碼如下:
void func(CCObject *obj)
{
ojb->retain();
ojb->release();
CCObject *pObj = obj;
...
...
pObj->release();
}
CCObject析構函數:
CCObject::~CCObject(void)
{
// if the object is managed, we should remove it
// from pool manager
if (m_uAutoReleaseCount > 0)
{
CCPoolManager::sharedPoolManager()->removeObject(this);
}
// if the object is referenced by Lua engine, remove it
....
}
由於Cocos2d-x裏有自己的內存自動管理機制,所以我們在清除對象的時候也可以不用去手動的清除(delete xxx),前提是使用了release,或autorelease。
析構函數裏只是做售後處理而已,當內存對象被釋放時,也應該從內存池中刪除引用。
上面我們知道,引用計數用來解決多處地方使用對象時的內存釋放問題。
下面通過CCObejct類,我們來看Cocos2d-x是如何實現自動管理內存的。
創建了對象之後,如果不想手動清除對象,那就使用autorelease()方法。每幀結束後,會自動釋放對象。
CCObject* CCObject::autorelease(void)
{
CCPoolManager::sharedPoolManager()->addObject(this);
return this;
}
void CCPoolManager::addObject(CCObject* pObject)
{
getCurReleasePool()->addObject(pObject);
}
void CCAutoreleasePool::addObject(CCObject* pObject)
{
m_pManagedObjectArray->addObject(pObject);
CCAssert(pObject->m_uReference > 1, "reference count should be greater than 1");
++(pObject->m_uAutoReleaseCount);
pObject->release(); // no ref count, in this case autorelease pool added.
}
上面代碼的邏輯較嚴格。
(1)m_pManagedObjectArray->addObject(pObject),一開始把對象添加到內存管理的隊伍中(此時就有了兩處地方使用了此對象)。
(2)斷言對象的引用數是否大於1。
(3)釋放對象。
總結一下CCObject:
1、提供了引用計數機制。
2、提供了內存自動管理機制的入口。
3、提供了複製對象的能力。
4、在這個版本里,有acceptVisitor(CCDataVisitor &visitor)方法,頭文件中是這樣說明的:
Visitor that helps to perform action that depends on polymorphic object type.
意思就是,這個類輔助去執行Action,Action動作取決於多態對象的類型。就是允許對象使用動作,不深入,以後看。
5、update()方法,因爲它主要是被繼承使用,在此沒有作用。
6、CCAutoreleasePool的友元類的作用是讓CCAutoreleasePool可以訪問此類的私有區域。(C++基礎內容)
有問題的地方希望能回覆我~