cocos2d-x 2.2.3 CCDictionary类简单分析

头文件

/**
 *  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。其他就没啥要点了。


你可能感兴趣的:(cocos2d-x 2.2.3 CCDictionary类简单分析)