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