【玩转cocos2d-x之二十六】数据结构CCDictionary

来源:互联网 发布:fleabag 知乎 编辑:程序博客网 时间:2024/04/30 15:00

原创作品,转载请标明http://blog.csdn.net/jackystudio/article/details/16958587


CCDictionary在cocos2d-x中被大量的应用,比如CCTexureCache,CCSpriteFramCache等等。


1.实现原理


1.1.uthash

CCDictionary是使用uthash实现的,而过时的CCMutableDictionary则是使用STL实现,就效率而言CCDictionary至少提升了两倍,而且CCDictionary并没有使用C++模版,因此也很容易绑定到脚本。

uthash是一个C/C++的哈希表实现,它以宏定义的方式实现了哈希表,不仅加快了运行速度,而且与key类型无关。它的github地址是https://github.com/troydhanson/uthash。cocos2d-x的头文件在\cocos2d-x-2.2.0\cocos2dx\support\data_support\uthash.h。

如果想在C++中直接使用也很简单,userguide在这里:http://troydhanson.github.io/uthash/userguide.html。可以很方便地进行增加,删除,查找,计数,迭代,排序等操作。


1.2.键(key)

uthash支持4种标准类型的键:整型,字符串,指针和结构体,不过到了CCDictionary就只支持整型和字符串型了。

[cpp] view plaincopy
  1. enum CCDictType  
  2. {  
  3.     kCCDictUnknown = 0,  
  4.     kCCDictStr,  
  5.     kCCDictInt  
  6. };  


2.CCDictElement

在了解CCDictionary之前还要看一下CCDictElement,很明显,CCDictElement是CCDictionary的一个元素,包含了一个key-value。key支持整型和字符串,使用的时候要注意在同一个CCDictionary中key类型必须要一致,value可以不一致。


3.API


3.1.创建

[cpp] view plaincopy
  1. //创建一个CCDictionary  
  2. static CCDictionary* create();  
  3. //用一个已存在的CCDictionary来创建一个新的CCDictionary  
  4. static CCDictionary* createWithDictionary(CCDictionary* srcDict);  
  5. //用一个plist来创建CCDictionary  
  6. static CCDictionary* createWithContentsOfFile(const char *pFileName);  
  7. //返回一个非autorelease对象的CCDictionary,它讷讷感够确保在新线程中使用  
  8. //但是你必须手动管理它的生命周期,当你不再需要它的时候,必须调用CC_SAFE_RELEASE  
  9. static CCDictionary* createWithContentsOfFileThreadSafe(const char *pFileName);  

3.2.查找

[cpp] view plaincopy
  1. //返回指定字符串类型key的value,如果CCDictionary的key是整型,会出现断言  
  2. CCObject* objectForKey(const std::string& key);  
  3. //返回指定整型key的value,如果CCDictionary的key是字符串型,会出现断言  
  4. CCObject* objectForKey(intptr_t key);  
  5. //返回指定字符串类型key的CCString,这里假定value是CCString型,如果不是或者未找到,则返回空串  
  6. const CCString* valueForKey(const std::string& key);  
  7. //返回指定整型类型key的CCString,这里假定value是CCString型,如果不是或者未找到,则返回空串  
  8. const CCString* valueForKey(intptr_t key);  

3.3.增加

[cpp] view plaincopy
  1. //插入一个key-value,如果是第一次调用,那么CCDictionary的key类型会被确定为字符串型,之后就不能插入整型key  
  2. //如果已存在该key,则旧key-value会被释放和移除,被新的替代  
  3. void setObject(CCObject* pObject, const std::string& key);  
  4. //插入一个key-value,如果是第一次调用,那么CCDictionary的key类型会被确定为整型,之后就不能插入字符串型key  
  5. //如果已存在该key,则旧key-value会被释放和移除,被新的替代  
  6. void setObject(CCObject* pObject, intptr_t key);  

3.4.移除

[cpp] view plaincopy
  1. //移除指定key  
  2. void removeObjectForKey(const std::string& key);  
  3. void removeObjectForKey(intptr_t key);  
  4. //移除一个CCArray中keys  
  5. void removeObjectsForKeys(CCArray* pKeyArray);  
  6. //通过元素来移除value  
  7. void removeObjectForElememt(CCDictElement* pElement);  
  8. //移除所有的key-value  
  9. void removeAllObjects();  

3.5.其他

[cpp] view plaincopy
  1. //返回一个随机元素,这个使用得注意,因为value可以不一样,所以返回类型每次都可能不同,在类型转换的时候要非常小心      
  2. CCObject* randomObject();  
  3. //返回一个包含所有key的CCArray  
  4. CCArray* allKeys();  
  5. //返回指定value的所有key,因为value是可以相同的,内部使用==比较两个value是否相同   
  6. CCArray* allKeysForObject(CCObject* object);  
  7. //返回元素个数  
  8. unsigned int count();  
  9. //把CCDictionary写到一个plist中,写入的value要求是字符串型  
  10. bool writeToFile(const char *fullPath);  

4.示例

[cpp] view plaincopy
  1. // Create a dictionary, return an autorelease object.  
  2. CCDictionary* pDict = CCDictionary::create();  
  3.   
  4. // Insert objects to dictionary  
  5. CCString* pValue1 = CCString::create("100");  
  6. CCString* pValue2 = CCString::create("120");  
  7. CCInteger* pValue3 = CCInteger::create(200);  
  8. pDict->setObject(pValue1, "key1");  
  9. pDict->setObject(pValue2, "key2");  
  10. pDict->setObject(pValue3, "key3");  
  11.   
  12. // Get the object for key  
  13. CCString* pStr1 = (CCString*)pDict->objectForKey("key1");  
  14. CCLog("{ key1: %s }", pStr1->getCString());  
  15. CCInteger* pInteger = (CCInteger*)pDict->objectForKey("key3");  
  16. CCLog("{ key3: %d }", pInteger->getValue());  
  17. CCString* pStr3=static_cast<CCString*>(pDict->randomObject());//这里有问题了,因为value有不同类型,所以随机返回时类型处理要小心  
  18. CCLog("{ random key: %s }",pStr3->getCString());              //如果返回的是整型pValue3,那么会出现断言  
  19. if(pDict->writeToFile("pdic.plist"))                          //整型的value无法写入,会提示This type cannot appear in property list  
  20.     CCLog("Write to file success!");  
Resource/pdic.plist

[html] view plaincopy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"/>  
  3.   
  4. <plist version="1.0">  
  5.     <dict>  
  6.         <key>key1</key>  
  7.         <string>100</string>  
  8.         <key>key2</key>  
  9.         <string>120</string>  
  10.         <key>key3</key>          <!key3对应整型数据无法写入/>  
  11.     </dict>  
  12. </plist>  

5.CCDICT_FOREACH


5.1.概况

宏定义,用于遍历CCDictionary的value。

[cpp] view plaincopy
  1. #define CCDICT_FOREACH(__dict__, __el__) \  
  2.     CCDictElement* pTmp##__dict__##__el__ = NULL; \  
  3.     if (__dict__) \  
  4.     HASH_ITER(hh, (__dict__)->m_pElements, __el__, pTmp##__dict__##__el__)  

5.2.示例

[cpp] view plaincopy
  1. CCDictElement* pElement;  
  2. CCDICT_FOREACH(dict, pElement)  
  3. {  
  4.     const char*key = pElement->getStrKey();  
  5.     // You certainly know the type of value, so we assume that it's a CCSprite.  
  6.     CCSprite* pSprite = (CCSprite*)pElement->getObject();  
  7.     // ......  
  8. }