Parse 搭建起了,说大实话用过两天,限制不少,但是个人开发够爆!在此记录一下,官方错误的代码示范以及分享我的使用经历。
1、初始搭建
在搭建服务器的文章里我有提到,现在还是写一写,需要自己写个类,初始化代码如下,变量填好
1 2 3 4 5 6 7 8 9 10 |
public string appid = "myAppId"; public string masterKey = "myMasterKey"; public string url; ParseClient.Initialize(new ParseClient.Configuration { ApplicationID = appid, Key = masterKey, ServerURI = url }); |
2、Parse类的规范
好的代码是需要封装到简单易懂的程序的,显然Parse给我们提供了子类,可惜文档没有跟上更新。下面贴出我的基类(对应服务后台的类)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
[ParseClassName("Player")] public partial class P_User : ParseObject { [ParseFieldName("name")] public string DisplayName { get { return GetProperty<string>(); } set { SetProperty(value); } } [ParseFieldName("highScore")] public int HighScore { get { return GetProperty<int>(); } private set { SetProperty(value); } } //官方的,调用有问题 //[ParseFieldName("displayName")] //public string DisplayName //{ // get { return GetProperty<string>("DisplayName"); } // set { SetProperty<string>(value, "DisplayName"); } //} } |
对应ParseServer 的 “Player”类,DisplayName对应该的是”name”变量,下一步,需要在在ParseObject里面进行注册,我是在Initialize 函数下就使用了:
1 |
ParseObject.RegisterSubclass<P_User>(); |
一般用法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
//取方法 ParseQuery<P_User> query = new ParseQuery<P_User>(); await query.GetAsync(UserId).ContinueWith(t => { Debug.Log("更新成功" + t.Result.ObjectId); curPlayer = t.Result; }); Debug.Log("我的名字是:" + curPlayer.DisplayName); //更新 curPlayer.DisplayName = "new Name"; await curPlayer.SaveAsync().ContinueWith(t => { if (t.Exception != null) Debug.LogError(t.Exception); else Debug.Log("Update is success!"); }); |
没有直接的调用变量方法,得手动使用Key,找highScore不等于0,按highScore降序排列,限制100个用户
1 2 3 4 5 6 7 8 9 |
private async System.Threading.Tasks.Task GetWorldRanksAsync() { var query = new ParseQuery<P_User>().WhereNotEqualTo("highScore", 0).OrderByDescending("highScore").Limit(100); await query.FindAsync().ContinueWith(t => { Debug.Log("update world rank successed"); }); } |
3、数据的保存限制128kb
一旦有个排行榜想查看别人的数据,这里就得考虑了数据的大小了,单个ParseObject限制是128K,其实也不算大,在此有几个解决方案提供
首先是优化你保存的字符串的大小,假如float,不用全部保存,精确到多少位就行了,举例
1 2 3 4 |
float f = 3.7003456f; var fString = f.ToString("f2"); //3.70 fString = float.Parse(fString); //3.7 |
其次是字符串优化,这里可以用到.net的GZip进行优化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
using System; using System.IO.Compression; using System.Text; using System.IO; /// <summary> /// Compresses the string. /// </summary> /// <param name="text">The text.</param> /// <returns></returns> public static string CompressString(string text) { byte[] buffer = Encoding.UTF8.GetBytes(text); var memoryStream = new MemoryStream(); using (var gZipStream = new GZipStream(memoryStream, CompressionMode.Compress, true)) { gZipStream.Write(buffer, 0, buffer.Length); } memoryStream.Position = 0; var compressedData = new byte[memoryStream.Length]; memoryStream.Read(compressedData, 0, compressedData.Length); var gZipBuffer = new byte[compressedData.Length + 4]; Buffer.BlockCopy(compressedData, 0, gZipBuffer, 4, compressedData.Length); Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gZipBuffer, 0, 4); return Convert.ToBase64String(gZipBuffer); } /// <summary> /// Decompresses the string. /// </summary> /// <param name="compressedText">The compressed text.</param> /// <returns></returns> public static string DecompressString(string compressedText) { byte[] gZipBuffer = Convert.FromBase64String(compressedText); using (var memoryStream = new MemoryStream()) { int dataLength = BitConverter.ToInt32(gZipBuffer, 0); memoryStream.Write(gZipBuffer, 4, gZipBuffer.Length - 4); var buffer = new byte[dataLength]; memoryStream.Position = 0; using (var gZipStream = new GZipStream(memoryStream, CompressionMode.Decompress)) { gZipStream.Read(buffer, 0, buffer.Length); } return Encoding.UTF8.GetString(buffer); } } |
数据比较大的时候还是优化了不少。
另一种思路是用Parse的嵌套功能。 但是实际上有没有效果我还不没有确认过
1 2 3 4 5 |
ParseObject parseobj = new ParseObject("Class"); ParseObject subObj = new ParseObject("SubClass"); parseobj["sub"] = subObj; parseobj.SaveAsync(); |
10月20号更新,Object嵌套功能,先说结论,高效可用,减少数据量,但是也有限制也有坑,注意别踩到了
上面的代码性展示是正确的,但是subObj是引用状态,也就是说当你直接 parseObj[“sub”]的时候,里面的变量都是空的,当你直接在parseobj.SaveAsync()的时候,也是不会产生作用的
- 取SubClass,单独写一次
- 改SubClass但是不引用不变,也需要单独的保存就OK
这次更新了排行榜,https://www.taptap.com/app/175964 想看的同学们可以试试。
4、不足的地方(坑)
1、当你在重定义类时,查询方法失败的运行,无法返回结果。所以你在首次建立数据时,又不希望字段undefined,那么就需要手动的赋值了。
1 2 3 4 |
public P_User() { HighScore = 0; } |
2、当变量是undefined时,查询判断语句无法进行判断(怎么判断都会有这条数据)
3、没有找到获取实时时间的方法。LeanCloud是有的。
4、2020年1月27号更新:
折腾一下午,后面加入了Try,才出报错:System.ArgumentException: You must call OrderBy before calling ThenBy.
妈蛋啊,方法拼错了,我把OrderByDescending 写错为 ThenBy 了,尼玛,,检查了一下午。哎,这报错提示不行
5、2020年3月19号更新:
之前版本的大BUG,虽然不影响总体,也不报错,但是就是SB了,代码注意像下面写就行,注释就是坑点
1 2 3 4 5 6 7 8 9 |
<del> /// <summary> /// 调用前判断空 /// </summary> [ParseFieldName("listObjectId")] public IList<string> ListObjectId { get { return GetProperty<IList<string>>(); } set { SetProperty(value); } }</del> |
即使你是从服务端取,也要判断,不然就SB了。不所报错的同时,,所有的await 都停在了那里。。
6、2020年3月20号更新:
针对第4与第5条,并非Parse的内核导致,而是在Unity里面使用Task功能时,Unity的错误调试将不在作用。
除非你把整段加上Try,而且有趣的是Task里面即使数组溢出,也不会对Unity游戏端有什么影响。程序还是稳稳的跑,只是await 会永久的停止在那里- –
5、灵异时间
在Unity5x (.net 4以下)本地测试连接不成功了我Cao,都2个小时候了,我的生命流逝得飞快,同样的配置,在Unity2019就木有问题了。
尼玛是闹哪样啊~