#ifndef __BASE_CCREF_H__
#define __BASE_CCREF_H__
#include "platform/CCPlatformMacros.h"
#include "base/ccConfig.h”//这里是关于使用什么东西的,想缩包就改宏
NS_CC_BEGIN //就是namespace cocos2d {
class Ref;
class CC_DLL Clonable//一个接口 规定了如何克隆
{
public:
virtual Clonable* clone() const = 0;
virtual ~Clonable() {};
CC_DEPRECATED_ATTRIBUTE Ref* copy() const
{
CC_ASSERT(false);
return nullptr;
}
};
class CC_DLL Ref //cocos2dx Node的老祖宗
{
public:
void retain(); //保留 引用加一
void release();//释放 引用减一
Ref* autorelease();// 自动释放 就是把自己添加到引用释放池中
unsigned int getReferenceCount() const;//返回引用计数
protected:
Ref();
public:
virtual ~Ref();
protected:
unsigned int _referenceCount;//引用计数
friend class AutoreleasePool;//把引用释放池作为友元类
#if CC_ENABLE_SCRIPT_BINDING //脚本相关 cocos2dx 可以使用lua javascript语言
public:
/// object id, ScriptSupport need public _ID
unsigned int _ID;
/// Lua reference id
int _luaID;
/// scriptObject, support for swift
void* _scriptObject;
#endif
// Memory leak diagnostic data (only included when CC_REF_LEAK_DETECTION is defined and its value isn't zero)
#if CC_REF_LEAK_DETECTION
public:
static void printLeaks();
#endif
};
class Node;
typedef void (Ref::*SEL_CallFunc)(); //函数指针
typedef void (Ref::*SEL_CallFuncN)(Node*);
typedef void (Ref::*SEL_CallFuncND)(Node*, void*);
typedef void (Ref::*SEL_CallFuncO)(Ref*);
typedef void (Ref::*SEL_MenuHandler)(Ref*);
typedef void (Ref::*SEL_SCHEDULE)(float);
#define CC_CALLFUNC_SELECTOR(_SELECTOR) static_cast<cocos2d::SEL_CallFunc>(&_SELECTOR) //#define ()中的是参数
#define CC_CALLFUNCN_SELECTOR(_SELECTOR) static_cast<cocos2d::SEL_CallFuncN>(&_SELECTOR)
#define CC_CALLFUNCND_SELECTOR(_SELECTOR) static_cast<cocos2d::SEL_CallFuncND>(&_SELECTOR)
#define CC_CALLFUNCO_SELECTOR(_SELECTOR) static_cast<cocos2d::SEL_CallFuncO>(&_SELECTOR)
#define CC_MENU_SELECTOR(_SELECTOR) static_cast<cocos2d::SEL_MenuHandler>(&_SELECTOR)
#define CC_SCHEDULE_SELECTOR(_SELECTOR) static_cast<cocos2d::SEL_SCHEDULE>(&_SELECTOR)
// Deprecated
#define callfunc_selector(_SELECTOR) CC_CALLFUNC_SELECTOR(_SELECTOR)
#define callfuncN_selector(_SELECTOR) CC_CALLFUNCN_SELECTOR(_SELECTOR)
#define callfuncND_selector(_SELECTOR) CC_CALLFUNCND_SELECTOR(_SELECTOR)
#define callfuncO_selector(_SELECTOR) CC_CALLFUNCO_SELECTOR(_SELECTOR)
#define menu_selector(_SELECTOR) CC_MENU_SELECTOR(_SELECTOR)
#define schedule_selector(_SELECTOR) CC_SCHEDULE_SELECTOR(_SELECTOR)
NS_CC_END // }
#endif // __BASE_CCREF_H__
-----------h和cpp的分割线----------------
#include "base/CCRef.h"
#include "base/CCAutoreleasePool.h"
#include "base/ccMacros.h"
#include "base/CCScriptSupport.h"
#if CC_REF_LEAK_DETECTION
#include <algorithm> // std::find
#endif
NS_CC_BEGIN
#if CC_REF_LEAK_DETECTION
static void trackRef(Ref* ref);
static void untrackRef(Ref* ref);
#endif
Ref::Ref()
: _referenceCount(1) // 等同与_referenceCount=1 _referenceCount(1)这么写对于class来说就是调用构造函数进行初始化,这种方式可以初始化const
{
#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
}
Ref::~Ref()
{
#if CC_ENABLE_SCRIPT_BINDING // 脚本相关
// if the object is referenced by Lua engine, remove it
if (_luaID)
{
ScriptEngineManager::getInstance()->getScriptEngine()->removeScriptObjectByObject(this);
}
else
{
ScriptEngineProtocol* pEngine = ScriptEngineManager::getInstance()->getScriptEngine();
if (pEngine != nullptr && pEngine->getScriptType() == kScriptTypeJavascript)
{
pEngine->removeScriptObjectByObject(this);
}
}
#endif
#if CC_REF_LEAK_DETECTION
if (_referenceCount != 0)
untrackRef(this);
#endif
}
void Ref::retain()
{
CCASSERT(_referenceCount > 0, "reference count should be greater than 0”);//断言必须_referenceCount > 0
++_referenceCount;
}
void Ref::release()
{
CCASSERT(_referenceCount > 0, "reference count should be 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))//在debug模式下如果引用计数已经为0并且这个对象还在自动释放池里面,报一个警告
{
CCASSERT(false, "The reference shouldn't be 0 because it is still in autorelease pool.");
}
#endif
#if CC_REF_LEAK_DETECTION
untrackRef(this);
#endif
delete this;
}
}
Ref* Ref::autorelease()
{
PoolManager::getInstance()->getCurrentPool()->addObject(this);
return this;
}
unsigned int Ref::getReferenceCount() const
{
return _referenceCount;
}
#if CC_REF_LEAK_DETECTION
static std::list<Ref*> __refAllocationList;
void Ref::printLeaks()
{
// Dump Ref object memory leaks
if (__refAllocationList.empty())
{
log("[memory] All Ref objects successfully cleaned up (no leaks detected).\n");
}
else
{
log("[memory] WARNING: %d Ref objects still active in memory.\n", (int)__refAllocationList.size());
for (const auto& ref : __refAllocationList)
{
CC_ASSERT(ref);
const char* type = typeid(*ref).name();
log("[memory] LEAK: Ref object '%s' still active with reference count %d.\n", (type ? type : ""), ref->getReferenceCount());
}
}
}
static void trackRef(Ref* ref)
{
CCASSERT(ref, "Invalid parameter, ref should not be null!");
// Create memory allocation record.
__refAllocationList.push_back(ref);
}
static void untrackRef(Ref* ref)
{
auto iter = std::find(__refAllocationList.begin(), __refAllocationList.end(), ref);
if (iter == __refAllocationList.end())
{
log("[memory] CORRUPTION: Attempting to free (%s) with invalid ref tracking record.\n", typeid(*ref).name());
return;
}
__refAllocationList.erase(iter);
}
#endif // #if CC_REF_LEAK_DETECTION
NS_CC_END