第一篇博客,先鼓個掌紀念一下,啪啪啪啪。。。
正文開始。
從 CCRef.h 開始
/** Interface that defines how to clone an Ref */
class CC_DLL Clonable
{
public:
/** returns a copy of the Ref 返回一個Ref的拷貝*/
virtual Clonable* clone() const = 0;
/**
* @js NA
* @lua NA
*/
virtual ~Clonable() {};
/** returns a copy of the Ref.
@deprecated Use clone() instead
*/
CC_DEPRECATED_ATTRIBUTE Ref* copy() const
{
// use "clone" instead
CC_ASSERT(false);
return nullptr;
}
};
關於開始的 CC_DLL,f12並沒有查到定義,後來到論壇,具體解釋http://www.ziliao1.com/Article/Show/716662CB4AD94EB2D020C3E74EA62A4C.html
class CC_DLL Ref
{
public:
/**
* Retains the ownership.保持所有權
*
* This increases the Ref's reference count.增加計數引用
*
* @see release, autorelease
* @js NA
*/
void retain();
在cpp文件中爲
void Ref::retain()
{
CCASSERT(_referenceCount > 0, "reference count should greater than 0");
++_referenceCount;
}
/**
* Release the ownership immediately.立即釋放所有權
*
* This decrements the Ref's reference count.縮減計數
*
* If the reference count reaches 0 after the descrement, this Ref is
* destructed.如果釋放後爲0,將自毀
*
* @see retain, autorelease
* @js NA
*/
void release();
在cpp文件中爲
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;
}
}
/**
* Release the ownership sometime soon automatically.自動釋放
*
* This descrements the Ref's reference count at the end of current在流的末尾自動測量計數
* autorelease pool block.
*
* If the reference count reaches 0 after the descrement, this Ref is
* destructed.
*
* @returns The Ref itself.
*
* @see AutoreleasePool, retain, release
* @js NA
* @lua NA
*/
Ref* autorelease();
Ref* Ref::autorelease()
{
PoolManager::getInstance()->getCurrentPool()->addObject(this);//PoolManager用於‘池’管理,獲取這個Ref對象後,通過<span style="font-family: Arial, Helvetica, sans-serif;">getCurrentPool加入自動釋放池</span>
return this;
}
還有一個getReferenceCount函數,用於返回計數,代碼就不貼了。
看看構造和析構。
首先是構造
Ref::Ref()
: _referenceCount(1) // when the Ref is created, the reference count of it is 1
{
#if CC_ENABLE_SCRIPT_BINDING
static unsigned int uObjectCount = 0;
_luaID = 0;
_ID = ++uObjectCount;
#endif
}
public:
/// object id, ScriptSupport need public _ID
unsigned int _ID;
/// Lua reference id
int _luaID;
析構
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 != NULL && pEngine->getScriptType() == kScriptTypeJavascript)
{
pEngine->removeScriptObjectByObject(this);
}
}
#endif
}
void LuaEngine::removeScriptObjectByObject(Ref* pObj)
{
_stack-><span style="color:#ff0000;"><strong>removeScriptObjectByObject</strong></span>(pObj);
ScriptHandlerMgr::getInstance()-><strong><span style="color:#33ccff;">removeObjectAllHandlers</span></strong>(pObj);
}
void LuaStack::<strong><span style="color:#ff0000;">removeScriptObjectByObject</span></strong>(Ref* pObj)
{
<span style="color:#ff0000;"><strong>toluafix_remove_ccobject_by_refid</strong></span>(_state, pObj->_luaID);
}
TOLUA_API int <span style="color:#ff0000;"><strong>toluafix_remove_ccobject_by_refid</strong></span>(lua_State* L, int refid)
{
void* ptr = NULL;
const char* type = NULL;
void** ud = NULL;
if (refid == 0) return -1;
// get ptr from tolua_refid_ptr_mapping
lua_pushstring(L, TOLUA_REFID_PTR_MAPPING);
lua_rawget(L, LUA_REGISTRYINDEX); /* stack: refid_ptr */
lua_pushinteger(L, refid); /* stack: refid_ptr refid */
lua_rawget(L, -2); /* stack: refid_ptr ptr */
ptr = lua_touserdata(L, -1);
lua_pop(L, 1); /* stack: refid_ptr */
if (ptr == NULL)
{
lua_pop(L, 1);
// Lua stack has closed, C++ object not in Lua.
// printf("[LUA ERROR] remove CCObject with NULL ptr, refid: %d\n", refid);
return -2;
}
// remove ptr from tolua_refid_ptr_mapping
lua_pushinteger(L, refid); /* stack: refid_ptr refid */
lua_pushnil(L); /* stack: refid_ptr refid nil */
lua_rawset(L, -3); /* delete refid_ptr[refid], stack: refid_ptr */
lua_pop(L, 1); /* stack: - */
// get type from tolua_refid_type_mapping
lua_pushstring(L, TOLUA_REFID_TYPE_MAPPING);
lua_rawget(L, LUA_REGISTRYINDEX); /* stack: refid_type */
lua_pushinteger(L, refid); /* stack: refid_type refid */
lua_rawget(L, -2); /* stack: refid_type type */
if (lua_isnil(L, -1))
{
lua_pop(L, 2);
printf("[LUA ERROR] remove CCObject with NULL type, refid: %d, ptr: %p\n", refid, ptr);
return -1;
}
type = lua_tostring(L, -1);
lua_pop(L, 1); /* stack: refid_type */
// remove type from tolua_refid_type_mapping
lua_pushinteger(L, refid); /* stack: refid_type refid */
lua_pushnil(L); /* stack: refid_type refid nil */
lua_rawset(L, -3); /* delete refid_type[refid], stack: refid_type */
lua_pop(L, 1); /* stack: - */
// get ubox
luaL_getmetatable(L, type); /* stack: mt */
lua_pushstring(L, "tolua_ubox"); /* stack: mt key */
lua_rawget(L, -2); /* stack: mt ubox */
if (lua_isnil(L, -1))
{
// use global ubox
lua_pop(L, 1); /* stack: mt */
lua_pushstring(L, "tolua_ubox"); /* stack: mt key */
lua_rawget(L, LUA_REGISTRYINDEX); /* stack: mt ubox */
};
// cleanup root
tolua_remove_value_from_root(L, ptr);
lua_pushlightuserdata(L, ptr); /* stack: mt ubox ptr */
lua_rawget(L,-2); /* stack: mt ubox ud */
if (lua_isnil(L, -1))
{
// Lua object has released (GC), C++ object not in ubox.
//printf("[LUA ERROR] remove CCObject with NULL ubox, refid: %d, ptr: %x, type: %s\n", refid, (int)ptr, type);
lua_pop(L, 3);
return -3;
}
// cleanup peertable
lua_pushvalue(L, LUA_REGISTRYINDEX);
lua_setfenv(L, -2);
ud = (void**)lua_touserdata(L, -1);
lua_pop(L, 1); /* stack: mt ubox */
if (ud == NULL)
{
printf("[LUA ERROR] remove CCObject with NULL userdata, refid: %d, ptr: %p, type: %s\n", refid, ptr, type);
lua_pop(L, 2);
return -1;
}
// clean userdata
*ud = NULL;
lua_pushlightuserdata(L, ptr); /* stack: mt ubox ptr */
lua_pushnil(L); /* stack: mt ubox ptr nil */
lua_rawset(L, -3); /* ubox[ptr] = nil, stack: mt ubox */
lua_pop(L, 2);
//printf("[LUA] remove CCObject, refid: %d, ptr: %x, type: %s\n", refid, (int)ptr, type);
return 0;
}
void ScriptHandlerMgr::<span style="color:#00cccc;"><strong>removeObjectAllHandlers</strong></span>(void* object)
{
if (NULL == object || _mapObjectHandlers.empty())
return;
auto iter = _mapObjectHandlers.find(object);
if (_mapObjectHandlers.end() != iter)
{
if (!iter->second.empty())
{
auto iterVec = iter->second.begin();
for (; iterVec != iter->second.end(); ++iterVec)
{
LuaEngine::getInstance()->removeScriptHandle<span style="color:#ffffff;">r</span>(iterVec->second);
}
(iter->second).clear();
}
_mapObjectHandlers.erase(iter);
}
}
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 callfunc_selector(_SELECTOR) static_cast<cocos2d::SEL_CallFunc>(&_SELECTOR)
#define callfuncN_selector(_SELECTOR) static_cast<cocos2d::SEL_CallFuncN>(&_SELECTOR)
#define callfuncND_selector(_SELECTOR) static_cast<cocos2d::SEL_CallFuncND>(&_SELECTOR)
#define callfuncO_selector(_SELECTOR) static_cast<cocos2d::SEL_CallFuncO>(&_SELECTOR)
#define menu_selector(_SELECTOR) static_cast<cocos2d::SEL_MenuHandler>(&_SELECTOR)
#define schedule_selector(_SELECTOR) static_cast<cocos2d::SEL_SCHEDULE>(&_SELECTOR)