Как использовать разбивку на страницы запросов Firestore с TableVIew - PullRequest
0 голосов
/ 19 июня 2020

Я пытаюсь использовать разбиение на страницы Firestore с быстрым TableView. Вот мой код, который загружает первые 4 сообщения из firestore.

func loadMessages(){
        let postDocs = db
            .collectionGroup("userPosts")
            .order(by: "postTime", descending: false)
            .limit(to: 4)

        postDocs.addSnapshotListener { [weak self](querySnapshot, error) in
            self?.q.async{
                self!.posts = []

                guard let snapshot = querySnapshot else {
                    if let error = error {
                        print(error)
                    }
                    return
                }

                guard let lastSnapshot = snapshot.documents.last else {
                    // The collection is empty.
                    return
                }

                let nextDocs = Firestore.firestore()
                    .collectionGroup("userPosts")
                    .order(by: "postTime", descending: false)
                    .start(afterDocument: lastSnapshot)

                if let postsTemp = self?.createPost(snapshot){

                    DispatchQueue.main.async {
                        self!.posts = postsTemp
                        self!.tableView.reloadData()
                    }
                }
            }
        }
    }

    func createPost(_ snapshot: QuerySnapshot) ->[Post]{
        var postsTemp = [Post]()
        for doc in snapshot.documents{
            if let firstImage = doc.get(K.FStore.firstImageField) as? String,
                let firstTitle = doc.get(K.FStore.firstTitleField) as? String,
                let secondImage = doc.get(K.FStore.secondImageField) as? String,
                let secondTitle = doc.get(K.FStore.secondTitleField) as? String,
                let userName = doc.get(K.FStore.poster) as? String,
                let uID = doc.get(K.FStore.userID) as? String,
                let postDate = doc.get("postTime") as? String,
                let votesForLeft = doc.get("votesForLeft") as? Int,
                let votesForRight = doc.get("votesForRight") as? Int,
                let endDate = doc.get("endDate") as? Int{
                let post = Post(firstImageUrl: firstImage,
                                secondImageUrl: secondImage,
                                firstTitle: firstTitle,
                                secondTitle: secondTitle,
                                poster: userName,
                                uid: uID,
                                postDate: postDate,
                                votesForLeft: votesForLeft,
                                votesForRight:votesForRight,
                                endDate: endDate)
                postsTemp.insert(post, at: 0)
            }else{

            }
        }
        return postsTemp
    }

Вот мой делегат, который также определяет конец TableView:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let post = posts[indexPath.row]
        let cell = tableView.dequeueReusableCell(withIdentifier: K.cellIdentifier, for: indexPath) as! PostCell
        cell.delegate = self

        let seconds = post.endDate
        let date = NSDate(timeIntervalSince1970: Double(seconds))
        let formatter = DateFormatter()
        formatter.dateFormat = "M/d h:mm"

        if(seconds <= Int(Date().timeIntervalSince1970)){
            cell.timerLabel?.text = "Voting Done!"
        }else{
            cell.timerLabel?.text = formatter.string(from: date as Date)
        }

        let firstReference = storageRef.child(post.firstImageUrl)
        let secondReference = storageRef.child(post.secondImageUrl)

        cell.firstTitle.setTitle(post.firstTitle, for: .normal)
        cell.secondTitle.setTitle(post.secondTitle, for: .normal)
        cell.firstImageView.sd_setImage(with: firstReference)
        cell.secondImageView.sd_setImage(with: secondReference)
        cell.userName.setTitle(post.poster, for: .normal)
        cell.firstImageView.layer.cornerRadius = 8.0
        cell.secondImageView.layer.cornerRadius = 8.0

        if(indexPath.row + 1 == posts.count){
            print("Reached the end")
        }

        return cell
    }

Раньше у меня был addSnapshotListener без ограничения на Query и просто снес все сообщения по мере их поступления. Однако я хотел бы ограничить количество сообщений, удаляемых за раз. Я не знаю, куда мне загружать данные в мою модель. Раньше он загружался в конце addSnapshotListener, и я все еще мог это сделать, но когда мне использовать next Query? Спасибо за любую помощь, и, пожалуйста, дайте мне знать, если я смогу подробнее рассказать о своем вопросе.

1 Ответ

2 голосов
/ 19 июня 2020

Существует метод UITableViewDelegate с именем tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath), который будет вызываться непосредственно перед загрузкой ячейки.

Вы можете использовать его, чтобы проверить, действительно ли строка в IndexPath является ячейкой последнего объекта в источнике данных вашего табличного представления. Что-то вроде datasource.count - 1 == IndexPath.row (-1 означает, что элемент 0 является первым элементом в массиве, хотя он уже считается как 1).

Если этот объект действительно является последним в вашем источнике данных, вы можете позвонить в Firebase и добавить элементы в источник данных. Перед изменением источника данных убедитесь, что новое количество объектов, которые показываются (уже загруженные + новые), должно быть больше, чем текущее количество объектов в источнике данных, в противном случае приложение испортит sh.

Вы также можете предупредить пользователя о том, что вы получаете данные. Вы можете вызвать это также в методе делегата.

...