[cocos2dx笔记016]cocos2dx 3.2 的UserDefault

[cocos2dx笔记016]cocos2dx 3.2 的UserDefault
本文地址:http://www.cppblog.com/zdhsoft/archive/2014/09/03/208216.html
本文基于cocos2dx 3.2
cocos2dx 提供了一个基于xml的用户数据存贮类,给基于cocos2dx开发的用户数据存贮,这个类名就是UserDefault,在cocos2dx 2.x中是CCUserDefault。我的程序用的就是这个,但是最近老出错,于是分析源代码,发现了一个让我震惊的东西。经过分析,发现用UserDefault每读写一次数据,都会创建一个tinyxml对象,然后读取xml内容。如果是写数据,还是写入xml一次。下面是对应的代码:
读取key,所以各种读取key的操作,都是类似这样。
double UserDefault::getDoubleForKey( const  char* pKey,  double defaultValue)
{
     const  char* value = nullptr;
    tinyxml2::XMLElement* rootNode;
    tinyxml2::XMLDocument* doc;
    tinyxml2::XMLElement* node;
    node =  getXMLNodeForKey(pKey, &rootNode, &doc);
     //  find the node
     if (node && node->FirstChild())
    {
        value = ( const  char*)(node->FirstChild()->Value());
    }

     double ret = defaultValue;

     if (value)
    {
        ret = utils::atof(value);
    }

     if (doc) delete doc;

     return ret;
}
 关于getXMLNodeForKey的实现
/* *
 * define the functions here because we don't want to
 * export xmlNodePtr and other types in "CCUserDefault.h"
 
*/

static tinyxml2::XMLElement* getXMLNodeForKey( const  char* pKey, tinyxml2::XMLElement** rootNode, tinyxml2::XMLDocument **doc)
{
    tinyxml2::XMLElement* curNode = nullptr;

     //  check the key value
     if (! pKey)
    {
         return nullptr;
    }

     do 
    {
         tinyxml2::XMLDocument* xmlDoc =  new tinyxml2::XMLDocument();
        *doc = xmlDoc;

        std:: string xmlBuffer = FileUtils::getInstance()->getStringFromFile(UserDefault::getInstance()->getXMLFilePath());

         if (xmlBuffer.empty())
        {
            CCLOG("can not read xml file");
             break;
        }
        xmlDoc->Parse(xmlBuffer.c_str(), xmlBuffer.size());

         //  get root node
        *rootNode = xmlDoc->RootElement();
         if (nullptr == *rootNode)
        {
            CCLOG("read root node error");
             break;
        }
         //  find the node
        curNode = (*rootNode)->FirstChildElement();
         while (nullptr != curNode)
        {
             const  char* nodeName = curNode->Value();
             if (!strcmp(nodeName, pKey))
            {
                 break;
            }

            curNode = curNode->NextSiblingElement();
        }
    }  while (0);

     return curNode;
}
关于setValueForKey的实现
static  void setValueForKey( const  char* pKey,  const  char* pValue)
{
     tinyxml2::XMLElement* rootNode;
    tinyxml2::XMLDocument* doc;
    tinyxml2::XMLElement* node;
     //  check the params
     if (! pKey || ! pValue)
    {
         return;
    }
     //  find the node
    node = getXMLNodeForKey(pKey, &rootNode, &doc);
     //  if node exist, change the content
     if (node)
    {
         if (node->FirstChild())
        {
            node->FirstChild()->SetValue(pValue);
        }
         else
        {
            tinyxml2::XMLText* content = doc->NewText(pValue);
            node->LinkEndChild(content);
        }
    }
     else
    {
         if (rootNode)
        {
            tinyxml2::XMLElement* tmpNode = doc->NewElement(pKey); // new tinyxml2::XMLElement(pKey);
            rootNode->LinkEndChild(tmpNode);
            tinyxml2::XMLText* content = doc->NewText(pValue); // new tinyxml2::XMLText(pValue);
            tmpNode->LinkEndChild(content);
        }    
    }

     //  save file and free doc
     if (doc)
    {
        doc->SaveFile(UserDefault::getInstance()->getXMLFilePath().c_str());
        delete doc;
    }
}
它的flush方法也有惊人的发现:
void UserDefault::flush()
{
}
它是一个空函数,也就是说,你在写入数据的时候,会以为最后会通过flush才会写入数据,没想全错了!
如果你用它存贮比较多的字段时,你就会现,你悲剧了。
幸好发现及时,这里不建议大家使用UserDefault做为你的数据存贮。
可以可以用自定义的方式文件读写
如可以通过标准的C读写 fopen,fwrite等或iostream也都可以,重点是读写的文件路径,会有所不同,下面是得到文件路径的例子
std::string strFullFileName = FileUtils::getInstance()->getWritablePath() + DATA_FILE_NAME;

最后:不要求写太高质量的代码,但也不要写的太低质量了

你可能感兴趣的:([cocos2dx笔记016]cocos2dx 3.2 的UserDefault)