如何与Firebase数据库分页?

时间:2018-08-22 21:32:28

标签: arrays swift firebase firebase-realtime-database

我正在尝试查询Firebase数据库,以便在JSQMessagesViewController中加载更多消息。初始化viewDidLoad后,我使用childAdded进行查询并获取最新的5条消息。

此后,我在didTapLoadEarlierMessagesButton中调用prepareToObserveOnce方法。其目的是观察一个类型为value的事件,并获得比早先下载的消息还旧的5条消息。

问题在于,调用prepareToObserveOnce时,消息将插入到数组的末尾,而不是开始。
当在print(" self.arrayOfItems is \( self.arrayOfItems)")中调用observeChildAddedMessages时,它会打印["11", "12", "13", "14", "15"],但是当我调用observeOnce(messageId: String)时,它会显示["11", "12", "13", "14", "15", "6", "7", "8", "9", "10"]。我的逻辑往南走。

-messages
  -LKQdzoSTGqjSWu78t7R
     messageUID:"-LKQdzoSTGqjSWu78t7R"
     senderUID: "UfGFsZ57jEdXyrtRzEZ1i3wOBZJ2"
     type: "text"


-chats
  -LKQduebP-TEGM95kE5N
      chatUID: "-LKQduebP-TEGM95kE5N"
      lastMessage: "15"
  -messageIds
      -LKQeAJFMi5fvrdv4Xl6: "-LKQdzoSTGqjSWu78t7R"

我的课程

 class ChatVC: JSQMessagesViewController {

       var oldestKey: String! //keeps track of the oldest key of the oldest message download
       var firstMessagesLoaded: Bool = false //enables us to assign the oldest key of the message downloaded once all messages have been downloaded in observeChildAddedMessages method
       var arrayOfItems = String() // for test purposes

       var chatSelected: Chat!  //chat received from MessagesViewController
       var currentUser: UserModel!
       var messages = [Message]()
       var jsqMessages = [JSQMessage]()


         override func viewDidLoad() {
           super.viewDidLoad()

          //when view first loads, this method is called and will download the most recent 5 messages sent in chat
           self.observeChildAddedMessages()
       }


        override func collectionView(_ collectionView: JSQMessagesCollectionView!, header headerView: JSQMessagesLoadEarlierHeaderView!, didTapLoadEarlierMessagesButton sender: UIButton!) {
        //when the headerView is touched, this method should download 5 more messages earlier than oldestKey

             self.prepareToObserveOnce()
         }

    }//end of class


    extension ChatVC {

     //read the messages from the chat (if any) when viewDidLoad is initialized
     func observeChildAddedMessages() {

        //  ~/chats/childByAutoId/messageIds
        let chatMessageIdsRef = chatSelected.chatRef.child("messageIds")

        chatMessageIdsRef.queryOrderedByKey().queryLimited(toLast: 5).observe(.childAdded, with: { (snapshot) in
            let messageId = snapshot.value as! String
            let messageKey = snapshot.key

            if self.firstMessagesLoaded == false {
                self.oldestKey = messageKey
                self.firstMessagesLoaded = true
            }

            // ~/messages/messageId
            let messagesRef = DDatabaseRReference.messages.reference()
            messagesRef.child(messageId).observeSingleEvent(of: .value, with: { (snapshot) in
                let message = Message(dictionary: snapshot.value as! [String : Any])

                if !self.messages.contains(message) {
                    let jsqMessage = JSQMessage(senderId: message.senderUID, displayName: message.senderDisplayName, text: message.text)
                    self.messages.append(message)
                    self.jsqMessages.append(jsqMessage!)
                     print(" self.arrayOfItems is \( self.arrayOfItems)")
                    self.finishReceivingMessage()
                 }
             })//end of messagesRef.child(messageId).observeSingleEvent
         })//end of chatMessageIdsRef.queryOrderedByKey()
      }//end of observeChildAddedMessages
    }//end extension


    extension ChatVC {

       func prepareToObserveOnce() {

         //  ~/chats/childByAutoId/messageIds
         let chatMessageIdsRef = chatSelected.chatRef.child("messageIds")

         if oldestKey == nil {

            chatMessageIdsRef.queryOrderedByKey().queryLimited(toLast: 5).observeSingleEvent(of: .value, with: { snapshot in

                guard snapshot.exists() else {return}
                let firstItem =  snapshot.children.allObjects.first as! DataSnapshot
                self.oldestKey = firstItem.key

                for item in snapshot.children.allObjects as! [DataSnapshot] {
                    let messageId = item.value as! String
                    self.observeOnce(messageId: messageId)
                }
            })

        } else {
             //get 5 more elements relative to oldestKey, meaning that we get the oldestKey inclusive. - .queryEnding(atValue: oldestKey)
            //These are earlier messages than currentKey
            chatMessageIdsRef.queryOrderedByKey().queryEnding(atValue: oldestKey).queryLimited(toLast: 6).observeSingleEvent(of: .value, with: { snapshot in

                guard snapshot.exists() else {return}
                let firstItem = snapshot.children.allObjects.first as! DataSnapshot

                for item in snapshot.children.allObjects as! [DataSnapshot] {
                    let messageId = item.value as! String
                    //avoid getting same message twice by checking the key of the message downloaded != currentKey
                    if firstItem.key != self.oldestKey {
                        self.observeOnce(messageId: messageId)
                    }
                 }
             })
         }  
      }//end prepareToObserveOnce
    }//end extension


    extension ChatVC {

      func observeOnce(messageId: String) {

          // ~/messages/messageId
         let messagesRef = DDatabaseRReference.messages.reference()
         messagesRef.child(messageId).observeSingleEvent(of: .value, with: { (snapshot) in
            let message = Message(dictionary: snapshot.value as! [String : Any])

            if !self.messages.contains(message) {

                let jsqMessage = JSQMessage(senderId: message.senderUID, displayName: message.senderDisplayName, text: message.text)

                self.messages.append(message)
                self.jsqMessages.append(jsqMessage!)
                 print(" self.arrayOfItems is \( self.arrayOfItems)")
            }
         })
       }//end of observeOnce
    }//end of extension

1 个答案:

答案 0 :(得分:0)

有两个问题。
1.是我将新消息附加到数组,而不是将它们插入索引0。

  1. 从firebase下载的消息以升序到达,因此我必须下载所有5个messageID,将它们分配给名为arrayOfMessageID的临时数组,然后遍历该数组并为每个messageID遍历self.observeOnce(messageId: messageID)。 br /> 在使用这种方法之前,在每个下载的messageID之后,我都在调用self.observeOnce(messageId: messageID),这样,在将消息分配给message或jsqMessages之前,我将无法对消息进行排序。或者可能有,但不是整洁的。

我的课程

  `class ChatVC: JSQMessagesViewController {`

       var oldestKey: String! //keeps track of the oldest key of the oldest message download
       var firstMessagesLoaded: Bool = false //enables us to assign the oldest key of the message downloaded once all messages have been downloaded in observeChildAddedMessages method
       var arrayOfItems = String() // for test purposes

       var chatSelected: Chat!  //chat received from MessagesViewController
       var currentUser: UserModel!
       var messages = [Message]()
       var jsqMessages = [JSQMessage]()


         override func viewDidLoad() {
           super.viewDidLoad()

          //when view first loads, this method is called and will download the most recent 5 messages sent in chat
           self.observeChildAddedMessages()
       }


        override func collectionView(_ collectionView: JSQMessagesCollectionView!, header headerView: JSQMessagesLoadEarlierHeaderView!, didTapLoadEarlierMessagesButton sender: UIButton!) {
        //when the headerView is touched, this method should download 5 more messages earlier than oldestKey

             self.prepareToObserveOnce()
         }

    }//end of class


    extension ChatVC {

     //read the messages from the chat (if any) when viewDidLoad is initialized
     func observeChildAddedMessages() {

        //  ~/chats/childByAutoId/messageIds
        let chatMessageIdsRef = chatSelected.chatRef.child("messageIds")

        chatMessageIdsRef.queryOrderedByKey().queryLimited(toLast: 5).observe(.childAdded, with: { (snapshot) in
            let messageId = snapshot.value as! String
            let messageKey = snapshot.key

            if self.firstMessagesLoaded == false {
                self.oldestKey = messageKey
                self.firstMessagesLoaded = true
            }

            // ~/messages/messageId
            let messagesRef = DDatabaseRReference.messages.reference()
            messagesRef.child(messageId).observeSingleEvent(of: .value, with: { (snapshot) in
                let message = Message(dictionary: snapshot.value as! [String : Any])

                if !self.messages.contains(message) {
                    let jsqMessage = JSQMessage(senderId: message.senderUID, displayName: message.senderDisplayName, text: message.text)
        //we can safely append messages here in .childAdded, because this method is called when viewDidLoad is initialized, so there are no other items in the array.
                     self.messages.append(message)
                     self.jsqMessages.append(jsqMessage!)
                     print(" self.arrayOfItems is \( self.arrayOfItems)")
                    self.finishReceivingMessage()
                 }
             })//end of messagesRef.child(messageId).observeSingleEvent
         })//end of chatMessageIdsRef.queryOrderedByKey()
      }//end of observeChildAddedMessages
    }//end extension


    extension ChatVC {

       func prepareToObserveOnce() {

         //  ~/chats/childByAutoId/messageIds
         let chatMessageIdsRef = chatSelected.chatRef.child("messageIds")

         if oldestKey == nil {

            chatMessageIdsRef.queryOrderedByKey().queryLimited(toLast: 5).observeSingleEvent(of: .value, with: { snapshot in

                guard snapshot.exists() else {return}
                let firstItem =  snapshot.children.allObjects.first as! DataSnapshot
                self.oldestKey = firstItem.key

                for item in snapshot.children.allObjects as! [DataSnapshot] {
                    let messageId = item.value as! String
                    self.observeOnce(messageId: messageId)
                }
            })

        } else {
             //get 5 more elements relative to oldestKey, meaning that we get the oldestKey inclusive. - .queryEnding(atValue: oldestKey)
            //These are earlier messages than currentKey
            chatMessageIdsRef.queryOrderedByKey().queryEnding(atValue: oldestKey).queryLimited(toLast: 6).observeSingleEvent(of: .value, with: { snapshot in

                guard snapshot.exists() else {return}
                let firstItem = snapshot.children.allObjects.first as! DataSnapshot

              //create an array of messageID in order to reverse the messages as they arrive in ascending order and we can nor append neither insert at a specific index because they would appear like [10,9,8,7]
            var arrayOfMessageID = [String]()

                for item in snapshot.children.allObjects as! [DataSnapshot] {
                    let messageId = item.value as! String
                    //avoid getting same message twice by checking the key of the message downloaded != currentKey
                    if firstItem.key != self.oldestKey {
                       arrayOfMessageID.append(messageId)
                    }
                 }
                     arrayOfMessageID.reverse()
                      for messageID in arrayOfMessageID {
                         self.observeOnce(messageId: messageID)
                     }
          //after downloading the messages is complete, set oldestKey as the firstItem downloaded. Remember, the download is done from low to high based on key timeStamp based, which means the firstItem downloaded is the oldest
                      self.oldestKey = firstItem.key
             })
         }  
      }//end prepareToObserveOnce
    }//end extension


    extension ChatVC {

      func observeOnce(messageId: String) {

          // ~/messages/messageId
         let messagesRef = DDatabaseRReference.messages.reference()
         messagesRef.child(messageId).observeSingleEvent(of: .value, with: { (snapshot) in
            let message = Message(dictionary: snapshot.value as! [String : Any])

            if !self.messages.contains(message) {

                let jsqMessage = JSQMessage(senderId: message.senderUID, displayName: message.senderDisplayName, text: message.text)

                    self.messages.insert(message, at: 0)
                    self.jsqMessages.insert(jsqMessage!, at: 0)

               //DO NOT append! Wrong way
                self.messages.append(message)
               self.jsqMessages.append(jsqMessage!)

                 print(" self.arrayOfItems is \( self.arrayOfItems)")
            }
         })
       }//end of observeOnce
    }//end of extension