【问题标题】:Firebase Query snapshot nil?Firebase 查询快照为零?
【发布时间】:2017-12-29 04:09:55
【问题描述】:

我正在创建一个简单的聊天应用程序来学习 Swift 和 Firebase。我有一个查询来检查聊天室的消息以加载到 tableView 中。该查询返回一个快照,但我无法正确存储和加载数据。我从快照中创建了一个字典,因此我可以获取各个子值,但它们返回 nil:

query.observeSingleEvent(of: .childAdded, with: { snapshot in

            print(snapshot)

            let indexPaths = self.messages.enumerated().map {
                IndexPath(row: $0.0, section: 0)
            }

            guard let messagesDict = snapshot.value as? [String:AnyObject] else { return }
            guard let sender = messagesDict["sender"] as? String else { return }
            guard let text = messagesDict["text"] as? String else { return }
            guard let timestamp = messagesDict["timestamp"] as? Int else { return }

            let message = Message.init(key: snapshot.key, sender: sender as! String, text: text as! String, timestamp: timestamp)

            self.messages.append(message)

            self.tableView.reloadData()
        })

po messagesDict在断点处返回数据:

▿ 1 element
  ▿ 0 : 2 elements
    - key : "-KotqLUUucaRagTRt967"
    ▿ value : 3 elements
      ▿ 0 : 2 elements
        - key : sender
        - value : eGTYRSo81JefgasYLRHUFHUTnEC3
      ▿ 1 : 2 elements
        - key : text
        - value : test
      ▿ 2 : 2 elements
        - key : timestamp
        - value : 1499914135546

应用程序到达我设置guard let sender 的下一个断点,但应用程序点击返回并停止执行其余代码块。如何正确访问发件人、文本和时间戳元素,以便将它们设置为变量并将它们存储在我的表的数组中?

任何帮助将不胜感激。我已经坚持了一段时间,我可以用另一双眼睛!

谢谢!!

其他信息:

查询:

let query = rootRef.child("chat-messages/\(chatKey)")

数据库结构:

{
  "chat-messages" : {
    "-KotqKI4zF9cS5XMR9WU" : {
      "-KotqLUUucaRagTRt967" : {
        "sender" : "eGTYRSo81JefgasYLRHUFHUTnEC3",
        "text" : "test",
        "timestamp" : 1499914135546
      }
    },
    "-KotqvBoFFzOTY6Q1fO7" : {
      "-KotqwGAJ85NuAp-Lh3Z" : {
        "sender" : "eGTYRSo81JefgasYLRHUFHUTnEC3",
        "text" : "test",
        "timestamp" : 1499914290279
      }
    },
    "-KotsNgF0ou5MIDn2l5K" : {
      "-KotsOSXw7OS_3xuXZgP" : {
        "sender" : "eGTYRSo81JefgasYLRHUFHUTnEC3",
        "text" : "test",
        "timestamp" : 1499914671997
      },
      "-KotsPqrCpipMLulNNFl" : {
        "sender" : "eGTYRSo81JefgasYLRHUFHUTnEC3",
        "text" : "test44",
        "timestamp" : 1499914677715
      }
    },
    "-Kotsv1Vv19dEF2q7XQu" : {
      "-KotsvYO9JvLY8gdTnA0" : {
        "sender" : "eGTYRSo81JefgasYLRHUFHUTnEC3",
        "text" : "test",
        "timestamp" : 1499914811675
      },
      "-KotsvxKXzIwbyvbwLPp" : {
        "sender" : "eGTYRSo81JefgasYLRHUFHUTnEC3",
        "text" : "test",
        "timestamp" : 1499914813335
      },
      "-Kotsw9vLiEf6KquU__e" : {
        "sender" : "eGTYRSo81JefgasYLRHUFHUTnEC3",
        "text" : "test",
        "timestamp" : 1499914814205
      },
      "-KotswHnzmfkEXih1O7y" : {
        "sender" : "eGTYRSo81JefgasYLRHUFHUTnEC3",
        "text" : "test",
        "timestamp" : 1499914814709
      },
      "-KotszHKBt254jZnUMAl" : {
        "sender" : "eGTYRSo81JefgasYLRHUFHUTnEC3",
        "text" : "test46456",
        "timestamp" : 1499914826967
      }
    },
    "-KoyheS01YxWExSNxl_H" : {
      "-Koyhf3G-FPEDrxQOcpU" : {
        "sender" : "eGTYRSo81JefgasYLRHUFHUTnEC3",
        "text" : "test",
        "timestamp" : 1499995746607
      }
    },
    "-Koyjc_aBaF1kFE-8Bll" : {
      "-Koyjd9PnO6sPOhS7P27" : {
        "sender" : "eGTYRSo81JefgasYLRHUFHUTnEC3",
        "text" : "test",
        "timestamp" : 1499996263096
      },
      "-KoyjdzSEi5twTVQMGOu" : {
        "sender" : "eGTYRSo81JefgasYLRHUFHUTnEC3",
        "text" : "test",
        "timestamp" : 1499996266491
      },
      "-Koyje2C9E524kV7nhLY" : {
        "sender" : "eGTYRSo81JefgasYLRHUFHUTnEC3",
        "text" : "test",
        "timestamp" : 1499996266730
      }
    },
    "-KpfUGw45F1FU2IrR87A" : {
      "sender" : "eGTYRSo81JefgasYLRHUFHUTnEC3",
      "text" : "test",
      "timestamp" : 1500746948396
    },
    "-KpfUHQGuTDi4yZutS5K" : {
      "sender" : "eGTYRSo81JefgasYLRHUFHUTnEC3",
      "text" : "test",
      "timestamp" : 1500746950368
    },
    "-KpfUHdSXeTzauATsDAP" : {
      "sender" : "eGTYRSo81JefgasYLRHUFHUTnEC3",
      "text" : "test",
      "timestamp" : 1500746951277
    },
    "-Kpfia0fXsoqpRtIr1kU" : {
      "sender" : "eGTYRSo81JefgasYLRHUFHUTnEC3",
      "text" : "gerg",
      "timestamp" : 1500750962815
    }
  },
  "chat-participants" : {
    "-KotqKI4zF9cS5XMR9WU" : {
      "eGTYRSo81JefgasYLRHUFHUTnEC3" : {
        "username" : "tester"
      }
    },
    "-KotqvBoFFzOTY6Q1fO7" : {
      "eGTYRSo81JefgasYLRHUFHUTnEC3" : {
        "username" : "tester"
      }
    },
    "-KotsNgF0ou5MIDn2l5K" : {
      "eGTYRSo81JefgasYLRHUFHUTnEC3" : {
        "username" : "tester"
      }
    },
    "-Kotsv1Vv19dEF2q7XQu" : {
      "eGTYRSo81JefgasYLRHUFHUTnEC3" : {
        "username" : "tester"
      }
    },
    "-KoyheS01YxWExSNxl_H" : {
      "eGTYRSo81JefgasYLRHUFHUTnEC3" : {
        "username" : "tester"
      }
    },
    "-Koyjc_aBaF1kFE-8Bll" : {
      "eGTYRSo81JefgasYLRHUFHUTnEC3" : {
        "username" : "tester"
      }
    },
    "-KpfLBjQdPiX2kSrl1yF" : {
      "eGTYRSo81JefgasYLRHUFHUTnEC3" : {
        "username" : "tester"
      }
    }
  },
  "chats" : {
    "-KotqKI4zF9cS5XMR9WU" : {
      "currentName" : "test",
      "date" : 1499914130657
    },
    "-KotqvBoFFzOTY6Q1fO7" : {
      "currentName" : "test",
      "date" : 1499914285904
    },
    "-KotsNgF0ou5MIDn2l5K" : {
      "currentName" : "test",
      "date" : 1499914668844
    },
    "-Kotsv1Vv19dEF2q7XQu" : {
      "currentName" : "test",
      "date" : 1499914809570
    },
    "-KoyheS01YxWExSNxl_H" : {
      "currentName" : "test",
      "date" : 1499995744095
    },
    "-Koyjc_aBaF1kFE-8Bll" : {
      "currentName" : "test",
      "date" : 1499996260740
    },
    "-KpfLBjQdPiX2kSrl1yF" : {
      "currentName" : "test3222",
      "date" : 1500744567786
    }
  },
  "user-chats" : {
    "eGTYRSo81JefgasYLRHUFHUTnEC3" : {
      "-KotqKI4zF9cS5XMR9WU" : {
        "chatKey" : "-KotqKI4zF9cS5XMR9WU",
        "currentName" : "test"
      },
      "-KotqvBoFFzOTY6Q1fO7" : {
        "chatKey" : "-KotqvBoFFzOTY6Q1fO7",
        "currentName" : "test"
      },
      "-KotsNgF0ou5MIDn2l5K" : {
        "chatKey" : "-KotsNgF0ou5MIDn2l5K",
        "currentName" : "test"
      },
      "-Kotsv1Vv19dEF2q7XQu" : {
        "chatKey" : "-Kotsv1Vv19dEF2q7XQu",
        "currentName" : "test"
      },
      "-KoyheS01YxWExSNxl_H" : {
        "chatKey" : "-KoyheS01YxWExSNxl_H",
        "currentName" : "test"
      },
      "-Koyjc_aBaF1kFE-8Bll" : {
        "chatKey" : "-Koyjc_aBaF1kFE-8Bll",
        "currentName" : "test"
      },
      "-KpfLBjQdPiX2kSrl1yF" : {
        "chatKey" : "-KpfLBjQdPiX2kSrl1yF",
        "currentName" : "test3222"
      }
    }
  },
  "user-friends" : {
    "36HDn5XyxjMCcMluJJ9KPBOCDMm1" : {
      "eGTYRSo81JefgasYLRHUFHUTnEC3" : {
        "username" : "tester"
      }
    },
    "eGTYRSo81JefgasYLRHUFHUTnEC3" : {
      "36HDn5XyxjMCcMluJJ9KPBOCDMm1" : {
        "username" : "tester2"
      }
    }
  },
  "user-invites" : {
    "eGTYRSo81JefgasYLRHUFHUTnEC3" : {
      "36HDn5XyxjMCcMluJJ9KPBOCDMm1" : {
        "username" : "tester2"
      }
    }
  },
  "users" : {
    "36HDn5XyxjMCcMluJJ9KPBOCDMm1" : {
      "email" : "tester2@test.com",
      "username" : "tester2"
    },
    "eGTYRSo81JefgasYLRHUFHUTnEC3" : {
      "email" : "test@test.com",
      "username" : "tester"
    }
  }
}

【问题讨论】:

  • 您有什么疑问?你的数据库结构呢?
  • 感谢您的帮助!我编辑了问题以包含查询和数据库结构。
  • @freeman 几天前我添加了一个建议的解决方案 - 解决问题还是仍有问题?

标签: ios swift firebase firebase-realtime-database


【解决方案1】:

你的字典看起来像:

▿ 1 element
  ▿ 0 : 2 elements
    - key : "-KotqLUUucaRagTRt967"
    ▿ value : 3 elements
      ▿ 0 : 2 elements
        - key : sender
        - value : eGTYRSo81JefgasYLRHUFHUTnEC3
      ▿ 1 : 2 elements
        - key : text
        - value : test
      ▿ 2 : 2 elements
        - key : timestamp
        - value : 1499914135546

但实际上它应该是这样的(如果你想访问字典[“sender”]):

▿ 2 elements
  ▿ 0 : 2 elements
    - key : sender
    - value : eGTYRSo81JefgasYLRHUFHUTnEC3
  ▿ 1 : 2 elements
    - key : text
    - value : test
  ▿ 2 : 2 elements
    - key : timestamp
    - value : 1499914135546

第一个解决方案:

您需要在查询中添加 .child("-KotqLUUucaRagTRt967")。

第二种解决方案:

你需要做这样的事情:

query.observe(.childAdded, with: { snapshot in
    for child in snapshot.children {
        guard let value = child.value as? NSDictionary else {
            return
        }

        guard let sender = value["sender"] as? String else {
            return
        }

        // You can user the sender
    }
})

更新:

query.observe(.childAdded, with: { snapshot in
    for child in snapshot.children.allObjects as! [FIRDataSnapshot] {
        if let value = child.value as? [String:Any], let sender = value["sender"] as? String {  
            // You can user the sender
        }
    }
})

注意

我用 observe 替换了 observeSingleEvent,正如 Frank van Puffelen 所说,这是 .childAdded 的不常见组合.

【讨论】:

  • 谢谢!我收到错误Value of type Any has no member value。它在value = child.value 上出错。有什么想法吗?
  • @freeman 你确定在value = child.value 之前包含guard let 吗?
  • @RajatKhare 是的,这行guard let value = child.value as? NSDictionary else {return} 上仍然有错误。 XCode 建议将其更改为 guard let value = (child as AnyObject).value as? NSDictionary else {return} 但随后会引发错误 Ambiguous use of value
【解决方案2】:

我认为您不需要 ChildAdded 处理程序,因此我使用了一个 observeSingleEvent 示例,因为您当时想在没有触发器的情况下从数据库中查询数据。当您使用observeSingleEvent 时,保持数据库同步很重要。我建议使用以下代码:

query.keepSynched(true) //keeps data in sync with database, if you have data persistince on in your appDelegate
query.observeSingleEvent(of: .value, with: { (snapshot) in //notice the changed here
            print(snapshot)
            //Since you want to loop again because there could be multiple
            //messages in that chatroom which all have a unique ID, do this loop:
            let enumerator = snapshot.children
            while let rest = enumerator.nextObject() as? FIRDataSnapshot {
               //this is 1 single message here
               let values = rest.value as? NSDictionary
               for (key, value) in values{
               print("Key: \(key), value: \(value)") 
               }
               //lets say you want to check if there is a value with a key named "text":
            let textUser = values?["text"] as? String ?? "No text found" 
               //providing a default value if there is no text. You could leave it empty, than it is nil (not recommend)
               //Not only is this a lot more readable, I do not use force unwrapping so your app 
               //cannot cause an exception.

               //Get more values from the dictionary as I did with textUser
               //Initialize message than here. You will see you do not need to force unwrap anything :D
               }

            }

        })

【讨论】:

  • “你和 Pipiks 将一个 observeSingleEvent 和一个 ChildAdded 结合起来,这两者不能同时使用”虽然这是一个不常见的组合,但没有技术原因不能将它们组合在一起。
  • 同意,不明白为什么不能将单个事件和 childAdded 结合起来?
  • @Yasir 我不确定,这就是为什么“我认为??!”。从我读到的文档中,每次添加新孩子时都会触发 childAdded 。 observeSingleEvent 将读取当时的数据。我认为这两个不能一起工作,但弗兰克已经纠正了我,我将把那部分编辑掉。
【解决方案3】:

正如 Pipiks 所解释的,您的问题是您试图访问比返回数据高一级的单个消息详细信息。

快照值为您提供聊天消息字典,其中顶级键是聊天消息键。要将返回的数据映射到消息数组,我将使用以下代码:

query.observeSingleEvent(of: .childAdded, with: { snapshot in

    guard let messagesDict = snapshot.value as? [String: AnyObject] else { return }

    self.messages = messagesDict.flatMap({ (messageId: String, messageData: Any) -> Message? in
        guard
            let sender = messageData["sender"] as? String,
            let text = messageData["text"] as? String,
            let timestamp = messageData["timestamp"] as? Int,
            let message = Message(key: messageKey, sender: sender, text: text, timestamp: timestamp) else {
                return nil
        }
        return message
    })

    self.tableView.reloadData()
})

它的作用是将您的消息字典映射到Message 对象数组。

我使用 flatMap 过滤掉任何没有发件人、文本或时间戳值的消息(因此 flatMap 返回 [Message] 对象)。

这能解决问题吗?

【讨论】:

  • 我省略了 indexPaths 代码,因为它看起来不像在任何地方使用 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多