具有Unity和Firebase数据库的词典数组-从键获取值

时间:2019-01-02 14:15:53

标签: c# firebase unity3d firebase-realtime-database

首先-我是Unity的新手。

我正在尝试从Firebase数据库中检索一些数据,将数据存储在字典的数组/列表中,然后使用该数组/列表显示来自服务器的数据。

所以...我的尝试方式:

1:创建字典数组以保存我的数据:

[System.Serializable]
public class Global
{
   public static Dictionary<string, object>[] offers;
}

2:处理来自数据库的数据,并将其存储在数组中:

void Handle_ChildAdded(object sender, ChildChangedEventArgs e)
    {
        if (e.DatabaseError != null)
        {
            Debug.LogError(e.DatabaseError.Message);
            return;
        }
        // Do something with the data in args.Snapshot
        if (e.Snapshot.Value != null)
        {
            var dict = e.Snapshot.Value as Dictionary<string, object>;

            if (dict != null)
            {
                Debug.Log(dict);
                Global.offers = new Dictionary<string, object>[Global.storesCount+1];
                Global.offers[Global.storesCount] = dict;
                Global.storesCount++;
                hasHaded = true;
            }
        }
    }

因此,现在我可以将数据库快照保存在Global.offers数组中。我应该得到的快照快照看起来像这样: enter image description here

是时候显示阵列中的数据了

到目前为止,一切都很好-因为现在我需要显示刚刚存储在Global.offers数组中的数据。 我尝试通过循环来做到这一点。我遍历数组并从数据库中搜索键,并实例化游戏对象预制体中的数据,如下所示:

 for (int i = 0; i < Global.storesCount; i++)
        {
            Transform scrollViewObj = Instantiate(prefab, new Vector3(0, (downSize * i) - firstY, 0), Quaternion.identity);
            scrollViewObj.transform.SetParent(scrollContent.transform, false);
            scrollViewObj.transform.Find("Overskift").gameObject.GetComponent<Text>().text = Global.offers[i]["Store"] as string;
            scrollViewObj.transform.Find("Text (1)").gameObject.GetComponent<Text>().text = Global.offers[i]["Headline"] as string;
            scrollViewObj.transform.Find("Text (2)").gameObject.GetComponent<Text>().text = "Din pris: " + Global.offers[i]["Price"] as string + " kr.";
            scrollViewObj.transform.Find("Text (3)").gameObject.GetComponent<Text>().text = "Spar: " + Global.offers[i]["AndresPris"] as string + " kr.";
        }

这是我遇到麻烦的地方。由于某些原因,Global.offers [i] [“ Store”]作为字符串== null,当然,这意味着我无法实例化该对象。我收到此错误:

NullReferenceException:对象引用未设置为对象的实例 LoadOffers.Start()(位于Assets / Scripts / LoadOffers.cs:36)

这太奇怪了,因为当我尝试调试时会得到一些矛盾的结果:

数组的长度为19。因此它不是空的。

当我尝试Debug.Log数组时我得到:

System.Collections.Generic.Dictionary`2 [System.String,System.Object] []

但是当我使用类似键的值搜索值时:

Debug.Log(Global.offers[0]["Store"]);

我得到的都是空。值输入后我搜索错误吗?还是其他人可以看到我在做什么错了?

1 个答案:

答案 0 :(得分:1)

问题

您的主要问题是Global.offers  是一个数组,因此具有固定的长度,因此不能如此简单地动态放大(您必须每次都复制该数组!)

您有点尝试在Handle_ChildAdded中解决此问题,但是排成一行

Global.offers = new Dictionary<string, object>[Global.storesCount+1];

您实际要做的是创建一个新的空(!)字典,数组的长度为Global.storeCount+1。您不会将当前值复制到新数组。

因此,在所有执行之后,您得到的只是一个只有null的数组。只有数组的最后一项内容才会来自

Global.offers[Global.storeCount] = dict;

因此仅实际设置最后一个值。看起来有点像

{null, null, null, null, ..., Dictionary<string, object> }

这就是长度为正确值的原因。您尝试访问的那一刻实际上已经抛出了异常

Global.offers[0]

null


解决方案

我建议完全不要使用数组,而应该使用List,与数组相反的是它可以动态增长

[System.Serializable]
public class Global
{
   public static List<Dictionary<string, object>> offers = new List<Dictionary<string, object>>();
}

并且比开始添加所有您实际上应该在哪里调用的字典填充列表之前要早

Global.offers.Clear();

重置列表,否则每次加载数据库时列表都会越来越大。另外,如果您完全确定只在不需要此功能时才致电,那么我总是建议您这样做,以便获得一个干净的,可正常使用的解决方案。

然后在其中添加元素

void Handle_ChildAdded(object sender, ChildChangedEventArgs e)
{
    if (e.DatabaseError != null)
    {
        Debug.LogError(e.DatabaseError.Message);
        return;
    }
    // Do something with the data in args.Snapshot
    if (e.Snapshot.Value != null)
    {
        var dict = e.Snapshot.Value as Dictionary<string, object>;

        if (dict != null)
        {
            Debug.Log(dict);
            Global.offers.Add(dict);
            hasHaded = true;
        }
    }
}

稍后,您以与数组中相同的方式访问List中的元素

Debug.Log(Global.offers[0]["Store"]);

请注意,您在解决方案中也不需要变量storeCount-您只需使用

Global.offers.Length

在此新解决方案中也不可用-您可以简单地使用

Global.offers.Count