关于PlayerPrefs 和 Easy Save 补充
原文地址:
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 配置禁止剔除的相关代码类
preserve=all 是保护当前命名空间下所有的类。
详情可见:
https://docs.unity3d.com/Manual/iphone-playerSizeOptimization.html
当然,我并没有采取这种方式,我毕竟是花了钱购买了插件,直接联系的Easy Save的作者,拿到了一份他修改过之后的unitypackage,不得不说,作者的反馈效率是非常高的。
2.Easy Save 3 存储的方式
经过测试,采用ES3File的方式,要比默认的读写效率更高。
在写入方面,ES3没有PlayerPrefs效率高的原因可以通过源代码直接的看到:
每一次存储,使用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 字典,迭代写入。
不要在Update中调用Save<T>,一般的频繁调用没问题。
更不要在Update中调用Sync,频繁的调用也要谨慎,我们可以放在关卡结束一类的地方,但特殊情况也有,比如玩家花钱买了钻石或是角色,这种重要数据是有必要即时存储的。
3.看到有的反馈说,反序列化属性无效
首先,属性是getter/setter,编译器会转换成方法,他并不是类的字段,可以在接口中定义,肯定是无法存储的。
感谢您的阅读, 如文中有误,欢迎指正,共同提高
欢迎关注我的技术分享的微信公众号,Paddtoning帕丁顿熊,期待和您的交流