您的位置:首页 > 移动开发 > Cocos引擎

cocos2d-x3.2 的UserDefault

2016-02-09 11:10 555 查看
[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;

最后:不要求写太高质量的代码,但也不要写的太低质量了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: