头文件
/**
* CCDictionary is a class like NSDictionary in Obj-C .
*
* @note Only the pointer of CCObject or its subclass can be inserted to CCDictionary.
* @code
* // 创建的示例
* CCDictionary* pDict = CCDictionary::create();
*
* // 插入的示例
* CCString* pValue1 = CCString::create("100");
* CCString* pValue2 = CCString::create("120");
* CCInteger* pValue3 = CCInteger::create(200);
* pDict->setObject(pValue1, "key1");
* pDict->setObject(pValue2, "key2");
* pDict->setObject(pValue3, "key3");
*
* // 获取key对应的obj的示例
* CCString* pStr1 = (CCString*)pDict->objectForKey("key1");
* CCLog("{ key1: %s }", pStr1->getCString());
* CCInteger* pInteger = (CCInteger*)pDict->objectForKey("key3");
* CCLog("{ key3: %d }", pInteger->getValue());
* @endcode
* @js NA
*
*/
// 一个obj可对应多个key 但是一个key只能对应一个obj
class CC_DLL CCDictionary : public CCObject
{
public:
CCDictionary();
~CCDictionary();
// 获取元素数目
unsigned int count();
// 获取所有元素的key 返回为array 当前还是autorelease的
CCArray* allKeys();
// 获取指定obj对应的所有key 使用==做判断
CCArray* allKeysForObject(CCObject* object);
// 获取数据
CCObject* objectForKey(const std::string& key);
CCObject* objectForKey(intptr_t key);
const CCString* valueForKey(const std::string& key);
const CCString* valueForKey(intptr_t key);
// 插入数据
// 注意:当你第一次调用set时,就确定了当前dict的key的类型是string还是int,后面set的key类型必须相同
// 另外,如果后面插入一个与之前插入的key相同的obj,那么之前的obj会被替换成新插入的这个
void setObject(CCObject* pObject, const std::string& key);
void setObject(CCObject* pObject, intptr_t key);
// 移除数据
void removeObjectForKey(const std::string& key);
void removeObjectForKey(intptr_t key);
void removeObjectsForKeys(CCArray* pKeyArray);
void removeObjectForElememt(CCDictElement* pElement);
void removeAllObjects();
/// @{
/// @name Function override
/**
* This function is used for deepcopy elements from source dictionary to destination dictionary.
* You shouldn't invoke this function manually since it's called by CCObject::copy.
* @lua NA
* @js NA
*/
virtual CCObject* copyWithZone(CCZone* pZone);
/// @}
// 随机获取数据
CCObject* randomObject();
// 创建
static CCDictionary* create();
static CCDictionary* createWithDictionary(CCDictionary* srcDict);
static CCDictionary* createWithContentsOfFile(const char *pFileName);
static CCDictionary* createWithContentsOfFileThreadSafe(const char *pFileName);
// 将dict写入一个plist文件
bool writeToFile(const char *fullPath);
/* override functions
* @lua NA
*/
virtual void acceptVisitor(CCDataVisitor &visitor);
private:
/**
* For internal usage, invoked by setObject.
*/
void setObjectUnSafe(CCObject* pObject, const std::string& key);
void setObjectUnSafe(CCObject* pObject, const intptr_t key);
public:
/**
* All the elements in dictionary.
*
* @note For internal usage, we need to declare this member variable as public since it's used in UT_HASH.
*/
CCDictElement* m_pElements;
private:
/** The support type of dictionary, it's confirmed when setObject is invoked. */
enum CCDictType
{
kCCDictUnknown = 0,
kCCDictStr,
kCCDictInt
};
/**
* The type of dictionary, it's assigned to kCCDictUnknown by default.
*/
CCDictType m_eDictType;
};
实现部分
实现部分只分析几个比较有趣的:
void CCDictionary::setObject(CCObject* pObject, const std::string& key)
{
CCAssert(key.length() > 0 && pObject != NULL, "Invalid Argument!");
// 第一次设置dict类型
if (m_eDictType == kCCDictUnknown)
{
m_eDictType = kCCDictStr;
}
CCAssert(m_eDictType == kCCDictStr, "this dictionary doesn't use string as key.");
CCDictElement *pElement = NULL;
HASH_FIND_STR(m_pElements, key.c_str(), pElement);
if (pElement == NULL) // 不存在 则插入
{
setObjectUnSafe(pObject, key);
}
else if (pElement->m_pObject != pObject) // 已存在 直接替换
{
// 替换方式:先移除原来的 再重新插入新的
CCObject* pTmpObj = pElement->m_pObject;
pTmpObj->retain();
removeObjectForElememt(pElement);
setObjectUnSafe(pObject, key);
pTmpObj->release();
}
}
void CCDictionary::removeObjectForKey(const std::string& key)
{
if (m_eDictType == kCCDictUnknown)
{
return;
}
CCAssert(m_eDictType == kCCDictStr, "this dictionary doesn't use string as its key");
CCAssert(key.length() > 0, "Invalid Argument!");
CCDictElement *pElement = NULL;
HASH_FIND_STR(m_pElements, key.c_str(), pElement);
removeObjectForElememt(pElement);
}
// 插入
void CCDictionary::setObjectUnSafe(CCObject* pObject, const std::string& key)
{
// 插入时 先对obj做retain elem要new出来 在elem内部不会做retain
pObject->retain();
CCDictElement* pElement = new CCDictElement(key.c_str(), pObject);
HASH_ADD_STR(m_pElements, m_szKey, pElement);
}
// 移除
void CCDictionary::removeObjectForElememt(CCDictElement* pElement)
{
if (pElement != NULL)
{
HASH_DEL(m_pElements, pElement);
pElement->m_pObject->release(); // 对obj做release操作
CC_SAFE_DELETE(pElement); // 删除elem
}
}
总结
内部实现主要还是一个hash表,不过是cocos2d-x内部的。
插入会做retain,移除会做release。其他就没啥要点了。