【问题标题】:Array of dictionaries with Unity and Firebase database - Get values from key具有 Unity 和 Firebase 数据库的字典数组 - 从键中获取值
【发布时间】:2019-05-29 04:39:14
【问题描述】:

首先 - 我是 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 数组中。我应该得到的快照效果如下所示:

是时候显示我的数组中的数据了

到目前为止一切正常 - 因为现在我需要显示我刚刚存储在 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"] as string == 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"]);

我得到的都是空的。我在价值观之后搜索错误吗?或者其他人可以看到我做错了什么吗?

【问题讨论】:

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


    【解决方案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
    

    【讨论】:

    • 非常感谢!我会简短地说:我爱你!在同一个代码上观看了这么多小时,只用另一个声明来修复。你是一个救生员!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-25
    • 1970-01-01
    • 2017-10-13
    • 1970-01-01
    相关资源
    最近更新 更多