【问题标题】:Firebase SortingFirebase 排序
【发布时间】:2017-05-24 16:17:27
【问题描述】:

基本上,我在 Firebase 上有一个应用。问题是,当 Firebase 对数据进行排序时,它会混淆数据,而不是按时间顺序。

我上网查了一下原因,发现是因为我用的是snapshot.value而不是snapshot.children。

但是,我不完全确定如何相应地更改代码,有人可以帮忙吗?

代码如下:

func retrieveChatLog() {

        FIRDatabase.database().reference().child("chats").child(chatID).observe(.value, with: {(snapshot) in

        let chats = snapshot.value as! [String : AnyObject]

        self.messages.removeAll()

        for (_, value) in chats {

            if let sender = value["sender"], let message = value["message"], let senderID = value["senderUID"], let date = value["date"] {

                let messageToShow = Message()

                messageToShow.message = message as! String

                messageToShow.sender = sender as! String

                messageToShow.senderUID = senderID as! String

                let formatter = DateFormatter()

                formatter.dateFormat = "dd.MM.yyyy"

                let curDate = formatter.date(from: date as! String)

                messageToShow.date = curDate as! Date

                if messageToShow.senderUID != "" {
                    self.messages.append(messageToShow)
                }
            }
        }
        self.tableView.reloadData()
    })
    FIRDatabase.database().reference().removeAllObservers()
}        

【问题讨论】:

    标签: ios firebase swift3 firebase-realtime-database


    【解决方案1】:

    问题不是因为您使用了 snapshot.value。您可以使用 .value 或 .childAdded。问题是,如果您使用 .value,您不想将快照转换为字典,因为字典不保留顺序。相反,您将需要强制转换为数组以保持顺序。这是您可以解决此问题的一种方法:

    FIRDatabase.database().reference().child("chats").child(chatID).observe(.value, with: {(snapshot) in
        let chats = snapshot.children.allObjects as! [FIRDataSnapshot]
        self.messages.removeAll()
    
        for chat in chats {
            if let value = chat.value as? [String: AnyObject] {
                if let sender = value["sender"], let message = value["message"], let senderID = value["senderUID"], let date = value["date"] {
    
                    let messageToShow = Message()
                    messageToShow.message = message as! String
                    messageToShow.sender = sender as! String
                    messageToShow.senderUID = senderID as! String
                    let formatter = DateFormatter()
                    formatter.dateFormat = "dd.MM.yyyy"
                    let curDate = formatter.date(from: date as! String)
                    messageToShow.date = curDate as! Date
                    if messageToShow.senderUID != "" {
                        self.messages.append(messageToShow)
                    }
                }
            }
        }
        self.tableView.reloadData()
    })
    FIRDatabase.database().reference().removeAllObservers()
    

    }

    【讨论】:

    • 它在线提供了 SIGABRT,其中 snapshot.value 被转换为 [FIRDataSnapshot]
    • 我的错!应该说snapshot.children.allObjects,而不是value。现在应该修好了。
    • 我得到了另一个 SIGABRT,但这次它说“无法将类型 '_NSCFConstantString' 的值转换为 'NSDictionary',但在上面说 chat.value 为! [字符串:AnyObject]
    • 同一行?因为这正是我在我的应用程序中的做法
    • 不是同一行...就是这个'let value = chat as! [字符串:AnyObject]'
    【解决方案2】:

    改变这一行 FIRDatabase.database().reference().child("chats").child(chatID).observe(.value, with: {(snapshot) in...

    到这个 FIRDatabase.database().reference().child("chats").child(chatID).observe(.childAdded, with: {(snapshot) in

    【讨论】:

      【解决方案3】:

      有一个公认的答案,但我想提供另一种可能更紧凑、更可扩展的解决方案。

      它从一个保存消息的类开始。在这种情况下,我只保留 firebase 密钥和时间戳,但可以轻松添加其他变量。您会注意到以相同格式从 Firebase 读取的时间戳变量:dd.mm.yy。如果需要,这对于排序很有用。另请注意,如果您想显示格式良好的 mm/dd/yyyy 格式,可以通过 formattedDate 计算属性获得。

      messagesArray 是 MessageClass 对象的数组,例如可以用作 tableView 的数据源。

      最后,加载所有消息的 loadMessages 函数。如另一个答案中所述,将快照转换为字典会失去排序保证。但是,如果我们直接迭代快照,则顺序保持不变。

      class MessageClass {
          var timestamp: String
          var fbKey: String
          var formattedDate: String {
              let formatter = DateFormatter()
              formatter.dateFormat = "dd.MM.yyyy"
              let d = formatter.date(from: timestamp)
      
              let outputFormattter = DateFormatter()
              outputFormattter.dateFormat = "MM/dd/yyyy"
              let finalDate = outputFormattter.string(from: d!)
      
              return finalDate
          }
      
          init(withSnap: DataSnapshot ) {
              let snapDict = withSnap.value as! [String: AnyObject]
              self.timestamp = snapDict["timestamp"] as! String
              self.fbKey = withSnap.key
          }
      }
      
      var messagesArray = [MessageClass]()
      
      func doButton0Action() {
      
          let messagesRef = self.ref.child("messages")
          messagesRef.observe(.value, with: { snapshot in
              for child in snapshot.children {
                  let snap = child as! DataSnapshot
                  let m = MessageClass(withSnap: snap)
                  self.messagesArray.append(m)
              }
              for msg in self.messagesArray { //test code to print the array once loaded
                  print("key: \(msg.fbKey)  date: \(msg.formattedDate)")
              }
          })
       }
      

      这段代码非常冗长,可以大大压缩,但可读性很强。 (它也需要保护和错误检查)。

      我强烈建议您将时间戳存储在一个

      yyyymmddhhmmss

      firebase 中的格式。它适用于排序/查询

      另外,作为旁注,不要依赖创建节点的日期(通过密钥)来保持排序,而是考虑在使用 .order(by:timestamp) 读取节点时利用时间戳。这将保证它们始终处于正确的顺序,即使消息被更改或密钥被修改。

      【讨论】:

        猜你喜欢
        • 2017-09-01
        • 1970-01-01
        • 2021-02-24
        • 1970-01-01
        • 1970-01-01
        • 2017-05-29
        • 1970-01-01
        • 2022-01-06
        • 2018-02-02
        相关资源
        最近更新 更多