仅从Firebase Snapshot Swift获取第一个对象

时间:2016-10-30 00:45:55

标签: swift firebase firebase-realtime-database

所以这是我的Firebase结构:

enter image description here

我试图获取所有图书图片(bookImage),将它们添加到列表中,然后使用此列表填充表格或其他任何内容。 (我使用swift 3)

struct item {
let picture: String!}

var items = [item]()
func getLatestAddedItems(){
    let databaseRef = FIRDatabase.database().reference()
    databaseRef.child("Items").observe(.childAdded, with: {
    FIRDataSnapshot in
        let picture = (FIRDataSnapshot.value as? NSDictionary)?["bookImage"] as? String ?? ""
        //self.items.insert(item(picture: picture), at: 0)
        self.items.append(item(picture: picture))
        print(self.items[0].picture)
        print(self.items[1].picture) // error here
    })}

我能够看到第一个打印输出,但是在第二个打印输出中我得到致命错误:索引超出范围,即使我的数据库中有3本书。

2 个答案:

答案 0 :(得分:2)

最后,我发布了解决方案:

func getLatestAddedItems(){
    let databaseRef = FIRDatabase.database().reference()
    databaseRef.child("Items").observe(.value, with: {
        snapshot in

        //self.items.insert(item(picture: picture), at: 0)
        for childSnap in snapshot.children.allObjects {

            let snap = childSnap as! FIRDataSnapshot
            print(snap.key)

            let picture = (snap.value as? NSDictionary)?["bookImage"] as? String ?? ""
            print(picture)
        }



    })
}

答案 1 :(得分:1)

由于您使用.childAdded,它会遍历数据树中每个对象的闭包,在本例中为每本书。当您尝试打印第二张图片时,它仍处于第一次迭代中。这意味着到目前为止您只检索了第一本书。这就是为什么你可以打印第一本书而不是第二本书。如果你将print语句移到闭包之外,然后在闭包迭代完所有三本书之后做了print语句,你就不会得到错误。

不要将其更改为.value,除非每次添加新的时候都要重新获得整个书籍列表。如果它有大量的书籍,那么每次都会有大量的数据。

摘要:.childAdded一次为您提供一本书,每本书都有一个新的快照。 .value在一个快照中为您提供所有书籍,然后您必须在闭包中自己迭代它们。恩。

for snap in snapshot.children {
// now you can do something with each individual item
}  

我也注意到你在闭包中使用了FIRDataSnapshot类型,它应该是一个代表你收到的快照的变量,而不是类型本身。将“FIRDataSnapshot in”更改为“snapshot in”快照,表示观察闭包给出了哪些信息,在本例中是一个FIRDataSnapshot类型的对象。

编辑:

您在下面提到的解决方案运行正常,但我会添加一个更干净,更易于使用的替代方案。

将一个init方法添加到Book类中,该方法将FIRDataSnapshot作为init参数,然后在查询Firebase时初始化该对象:

 struct Book {
 let bookImageString: String

  init?(snapshot: FIRDataSnapshot) {
     guard let snap = snapshot.value as? [String : AnyObject], let urlString = snap["bookImage"] else { return nil }
     bookImageString = imageString
   {
{

然后当你查询firebase时,你可以这样做:

for snap in snapshot.children {
  if let snap = snap as? FIRDataSnapshot, let book = Book(snapshot: snap) {
 self.items.append(book)
    { 
}
这样做可以清理代码并减少代码中出错的可能性。

此外,由于您使用.value,请确保在关闭的开头清空数据源数组,否则在添加新书时会出现重复。

 items.removeAll()