当时被问到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++基础内容)
有问题的地方希望能回复我~