关于PlayerPrefs 和 Easy Save 补充

发表于2019-07-29
评论0 7.9k浏览

原文地址:

https://mp.weixin.qq.com/s?__biz=MzU3MDc5MzYxNQ==&mid=2247483820&idx=1&sn=35facb890eda7832e6b1b5d14a827dde&chksm=fceb4a4ccb9cc35af7c40890a44ce6fd0c83b07e9df1f7138f88d328e6d9a90f3fe58f7f32c6&token=988594013&lang=zh_CN#rd


 

概括Easy Save 3 -一款增强版的PlayerPrerfs数据存储插件,提供了更多的类型,组件读写的支持,支持加密,配置简单,代码结构清晰轻量。


 

Easy Save 3 在项目中,使用了一段时间,还算不错,比较省事儿,碰到几个小问题,在这里陈述一下:


 

1.真机运行,异常提示:


 

ES3Type for primitive could not be found. but the type list has been initialized and is not empty.


 

原因:

Player Settings->Managed Stripping Level = Medium or High


 

开启代码剔除的设置,打包时,会将某些Class从代码中,进行剔除,以减少代码的加载时间,通常我们都是要开启这一项,以获得代码层面的优化,

针对这种情况,解决方法就是禁止Unity剔除相关的代码。


 

在Assets/下加入link.xml 配置禁止剔除的相关代码类


 

640?wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1


 

preserve=all 是保护当前命名空间下所有的类。


 

详情可见:

https://docs.unity3d.com/Manual/iphone-playerSizeOptimization.html


 

当然,我并没有采取这种方式,我毕竟是花了钱购买了插件,直接联系的Easy Save的作者,拿到了一份他修改过之后的unitypackage,不得不说,作者的反馈效率是非常高的。


 

2.Easy Save 3 存储的方式


 

经过测试,采用ES3File的方式,要比默认的读写效率更高。

在写入方面,ES3没有PlayerPrefs效率高的原因可以通过源代码直接的看到:


 

640?wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1

每一次存储,使用IO MemoryStream处理,这里就肯定要比PlayerPrefs慢了,cache[key],Easy Save 3维护了一个


 

private Dictionary<string, ES3Data> cache = new Dictionary<string, ES3Data>();


 

字典,我们每一次Save都会更新字典中的Value


 

cache[key] = new ES3Data(es3Type, stream.ToArray());


 

这里之前有个使用误区,我以为cache和我当前要存储的对象是一种引用关系,如果我改变了对象的值,那么cache下对应的value 也要进行改变。


 

这是错误的,cache会在堆内存中重新分配一块内存区域进行管理,如果我们想要存储对象的数据,每次都要调用Save<T>。


 

注意,不要在Update中去调用。


 

还有一种情况,通常为了方便,数值在改变的时候,会主动调用一次Save<T>,但如果我们的逻辑中,要在一个很大的循环中去循环改变数值,那么最好将Save<T>放在循环的外部,避免多次不必要的调用。


 

Save<T>和PlayerPrefs一样,只是更新内存中的数据,并没有写入到磁盘,需要我们在必要的时候,手动进行调用。这里的时机可以放在很多地方,

比如场景切换后,关卡结束后等等,或是中断和退出的回调等等。


 

写入到本地的操作最好不要在游戏中频率的调用,尤其是数据比较大的情况,可能会引起微卡顿,Easy Save 3 通过调用Sync即可将数据写入到本地。代码很简单,遍历cache 字典,迭代写入。
 


 

640?wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1


 

不要在Update中调用Save<T>,一般的频繁调用没问题。

更不要在Update中调用Sync,频繁的调用也要谨慎,我们可以放在关卡结束一类的地方,但特殊情况也有,比如玩家花钱买了钻石或是角色,这种重要数据是有必要即时存储的。


 

3.看到有的反馈说,反序列化属性无效


 

首先,属性是getter/setter,编译器会转换成方法,他并不是类的字段,可以在接口中定义,肯定是无法存储的。

 

感谢您的阅读, 如文中有误,欢迎指正,共同提高


 

欢迎关注我的技术分享的微信公众号,Paddtoning帕丁顿熊,期待和您的交流

 

iOIWBCwZkEenjYhorLAF.jpg
  • 允许他人重新传播作品,但他人重新传播时必须在所使用作品的正文开头的显著位置,注明用户的姓名、来源及其采用的知识共享协议,并与该作品在磨坊上的原发地址建立链接
  • 可对作品重新编排、修改、节选或者以作品为基础进行创作和发布
  • 可将作品进行商业性使用

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引