firebase RTD 中的 Swift 数组返回元素之间的无效值

问题描述 投票:0回答:1

我有一个 json,由于某种奇怪的原因,它返回两个不同的值,一个是数组,其余的是字典,这使得解析变得困难。

这是创建 JSON 元素的相关代码

 func crtJson() -> [AnyHashable: Any] {
        
        let myDays = [
                        "1": ["Chap": ["1":"0", "2":"0", "3":"0", "4":"0"], "Comp": "0"],
                        "2": ["Chap": ["5":"0", "6": "0", "7": "0", "8": "0"], "Comp": "0"],
                        "3": ["Chap": ["9":"0", "10": "0", "11": "0", "12": "0"], "Comp": "0"],
                        "4": ["Chap": ["13":"0", "14": "0", "15": "0", "16": "0", "17": "0"], "Comp": "0"],
                        "5": ["Chap": ["18":"0", "19": "0", "20": "0"], "Comp": "0"],
                        "6": ["Chap": ["21":"0", "22": "0", "23": "0"], "Comp": "0"],
                        "7": ["Chap": ["24":"0", "25": "0"], "Comp": "0"],
                        "8": ["Chap": ["26":"0", "27": "0", "28": "0"], "Comp": "0"],
                        "9": ["Chap": ["29":"0", "30": "0", "31": "0"], "Comp": "0"]
                     ]
        print(myDays)
        let jsonObject: [String: Any] = [
            "Days": myDays
        ]


        let valid = JSONSerialization.isValidJSONObject(jsonObject) // true
        print(jsonObject)
            return jsonObject
    }

您会注意到,除了 CHAP 元素的数量之外,我对其进行了完全相同的编码,这不会产生任何影响。

当我尝试使用以下代码阅读此内容时

func validateBook(mDay: Int) {
    var intArray = [Any]()
    let ref = Database.database()
    let firUser = Auth.auth().currentUser
    let myPath = "users/\(firUser!.uid)/Yrly/Days/\(mDay)/Chap"
    let myRef1 = ref.reference().child(myPath)
    print(myRef1.url)
    myRef1.observe(.value, with: {
        snapshot in
        print(snapshot.value)
        let myArray = snapshot.value as! NSArray
        for n in 1...(myArray.count - 1)  {
            if (myArray[n] as! String) != "3" {
                self.retVal = false
            }
        }
        if self.retVal == true {
            // Update day to completed
            print("Day completed")
            let ref = Database.database().reference()
            let pathString = self.firuser! + "/Yrly/Days/\(String(mDay))/"
            print(pathString)
            let post = ["Comp": "3"]
            ref.child("users").child(pathString).updateChildValues(post)
        }
    })
}

我得到第一个元素的以下值:(我的意思是第一个元素是第 1 天)

Optional(<__NSArrayM 0x600000db4300>(
<null>, 
3,
0,
0,
0
)
)

对于所有其他元素:

Optional({
5 = 3;
6 = 0;
7 = 0;
8 = 0;
})
Could not cast value of type '__NSDictionaryM' (0x1f1d06c88) to 'NSArray' (0x1f1d02048).

那么为什么它将第一天作为数组读取,而将其他所有内容作为字典读取?

我尝试将以下行更改为字典:

let myArray = snapshot.value as! NSArray

以下: 让 myArray = snapshot.value 为! NS词典

它也会爆炸。 由于某种原因,它总是使第一个元素成为数组,而其他所有元素成为字典。

arrays swift firebase dictionary firebase-realtime-database
1个回答
0
投票

使用顺序数字索引作为 Firebase 实时数据库结构中的键是一种反模式,正是因为您遇到了这种行为。


Firebase 实时数据库将数组存储为带有数字键的键/值对。所以当你有一个数组时:

["first", "second", "third"]

Firebase 实际上将其存储为:

{
  "0": "first",
  "1": "second",
  "2": "third"
}

然后,当客户端(REST API 或 SDK)读取此数据时,它会检测顺序键的模式并将其转换回数组。

当您有一个实际的数组时,这非常有用,但当您获取数据的子集(通过查询)时,或者当您有一个非数组对象,而您恰好使用(几乎)顺序数字作为键时,这会崩溃。根据确切的结果,SDK 可能会填充数组中缺失的条目(第一个结果中的

<null>
或完全不执行数组强制转换。


解决方案是遵循最佳实践,并且使用数组索引作为 Firebase 实时数据库中的键。我经常使用的一个简单解决方法是在键前添加一个短字母数字值。

{
  "key_0": "first",
  "key_1": "second",
  "key_2": "third"
}

另请参阅最佳实践:Firebase 中的数组(距今已有十多年历史了🤯)。

© www.soinside.com 2019 - 2024. All rights reserved.