cocos2d-x之__Array:: createWithContentsOfFile引发的“血案”

cocos2d-x之__Array:: createWithContentsOfFile引发的“血案”,第1张

概述*************************************************************************** 时间:2014-11-8 作者:Sharing_Li 转载出处:http://www.voidcn.com/article/p-cccqrmwi-rx.html *******************************************

***************************************************************************

时间:2014-11-8

作者:Sharing_li

转载出处:http://www.jb51.cc/article/p-cccqrmwi-rx.html

***************************************************************************

昨天写代码,想从一个pList文件中读取一个数组,如下所示:

<?xml version="1.0" enCoding="UTF-8"?><!DOCTYPE pList PUBliC "-//Apple//DTD PList 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><pList version="1.0"><array>	<dict>		<key>x</key>		<integer>12</integer>		<key>y</key>		<integer>20</integer>	</dict>	<dict>		<key>x</key>		<integer>17</integer>		<key>y</key>		<integer>25</integer>	</dict></array></pList>

用的方法是cocos2d-x3.2版本的__Array::createWithContentsOffile("xxxxx.pList");结果读取失败,程序一运行直接崩溃,提示什么断言错误。一开始以为自己的pList文件格式不对,但一查资料,发现格式是对的,没什么问题。网上看了下别人用的2.x版本也没什么问题,然后对比了下2.x和3.x的数据存储结构,终于发现了问题的所在。

在2.x版本中,使用CCArray可以保存不同数据类型的数据,使用createWithContentsOffile生成Array没有问题。但是到了3.x版本中,用cocos2d::Vector替代了CCArray的功能,cocos2d::Vector<T>中的T必须是一个指向cocos2d::Ref子类对象的指针,不能是其他数据类型或者是原生类型(即基本类型),因为开发人员已经将Cocos2dx的内存管理模型集成到cocos2d::Vector<T>中,并且Vector自己并不是Ref的子类,所以不能对它的实例使用retain和release。在3.x版本中虽然有__Array,但已被弃用了,只保留了CCArray的部分功能。

以前面的__Array::createWithContentsOffile("xxxxx.pList");为例,我们按F12跟踪查看源代码:

__Array* __Array::createWithContentsOffile(const std::string& filename){    __Array* ret = __Array::createWithContentsOffileThreadSafe(filename);    if (ret != nullptr)    {        ret->autorelease();    }    return ret;}__Array* __Array::createWithContentsOffileThreadSafe(const std::string& filename){    ValueVector arr = fileUtils::getInstance()->getValueVectorFromfile(filename);        __Array* ret = __Array::createWithCapacity(static_cast<int>(arr.size()));    for(const auto &value : arr) {        ret->addobject(__String::create(value.asstring()));    }        return ret;}

之前崩溃的原因是在于这一句代码:ret->addobject(__String::create(value.asstring()));因为我们的pList文件里面没有string类型,而这里好像只能读取string类型,所以读取失败。我们读取的pList文件中可以看到有int等基本类型,他不是Ref的子类,所以不能用cocos2d::Vector方法,并且Vector也没有提供createWithContentsOffile方法。那么既然__Array和Vector都不行,那怎么解决呢?

放心,引擎给我们提供了保存非Ref子类的容器类,就是ValueVector,它在文档中如下定义:

typedef std::vector<Value> ValueVector;

可以看到,ValueVector实际上就是一个存放Value类型元素的std::vector容器。在3.2中,我们可以用如下方法读取pList:

ValueVector val = fileUtils::getInstance()->getValueVectorFromfile("star.pList");for(auto ref : val) {	//将val 里面读取的对象ref 转化为ValueMap 类型	auto temp_map = ref.asValueMap();	//转化之后的Val 对象 temp_map 取出x,y值	auto x = temp_map.at("x").asInt();	auto y = temp_map.at("y").asInt();}

不过用ValueVector读取的pList文件只局限于是该pList的格式的以array数组类型开头的,例如下面这种:

<array>      <dict>          <key>name</key>          <string>star</string>          <key>number</key>          <integer>yes</integer>      </dict>  </array>

如果是以dict字典类型开头的文件,则要换用ValueMap。

拓展:

1、从前面的讨论当中,我们不难得出:ValueVector中可以放ValueVector,前提是将ValueVector转成Value类型;而Vector中不能存放Vector类型的元素。(不知道为什么的可以再重头看一遍)。

2、另外在查看ValueVector源码时发现的一个需要注意的地方,删除ValueVector中的元素有两种方法:

A、val.pop_back();直接删除容器中最后一个元素。

B、用erase删除容器中的某一个元素,使用的方法是:

auto iter = std::find(val.begin(),val.end(),x); val.erase(iter); 而不是star_val.erase(x);(鄙人曾经就放过这个错误)因为erase的参数是一个迭代器,更深层的原因是Value没有重载==运算符,而std::find里面的数据类型必须实现==运算符,否则就不能查找,那么也就不能删除元素了。

总结

以上是内存溢出为你收集整理的cocos2d-x之__Array:: createWithContentsOfFile引发的“血案”全部内容,希望文章能够帮你解决cocos2d-x之__Array:: createWithContentsOfFile引发的“血案”所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1008964.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-22
下一篇 2022-05-22

发表评论

登录后才能评论

评论列表(0条)

保存