首页 > 解决方案 > Xcode 说我的数组超出范围,但我可以确认我的数组没有超出范围

问题描述

我有一个用于我的 TableView 单元的数组,类似于 Facebook 提要。我已经成功地让我的应用程序版本的 Feed 成功显示用户发帖的日期、显示创建帖子的用户电子邮件、显示随帖子上传的照片,但我似乎无法弄清楚如何为他们的用户个人资料制作一个数组。所有信息都是从 Firebase 中提取的。

下面你可以看到我的数据库结构的屏幕截图。

在这里,您可以看到我存储帖子信息的帖子结构。

Posts > DocumentID > PostInformation(日期、上传的图片 url 为字符串、海报电子邮件,如计数为 Int)

帖子数据库结构


表视图

我正在尝试从另一个名为 Public 的集合中提取用户的个人资料。

公共 > 用户电子邮件 (test@gmail.com) > 用户信息(姓名、日期、个人资料照片网址)

公共数据库结构

我从获取 Firestore 数据库的信息中获得了帖子信息,并将所有内容都放入了一个数组中。

然后我将所有内容加载到 tableview 单元格中。

//发布变量 var userCommentArray = String

var likeArray = [Int]()

var userPostImageArray = [String]()

var userProfilePhotoArray = [String]()

var userPostDescription = [String]()

var PosterEmail = [String]()

var postDate = [String]()

var documentIDArray = [String]()

以上是我的帖子变量

下面是我的单元格和用于加载其信息的数组。

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let Cell = tableView.dequeueReusableCell(withIdentifier: "VidaFeed", for: indexPath) as! FeedCell
    print("Posteremail count = \(PosterEmail.count)")

   >> //Cell.userProfilePhotoFeedCellLabel.sd_setImage(with: URL(string: self.userProfilePhotoArray[indexPath.row]))
    Cell.FeedCellUserNameLabel.text = PosterEmail[indexPath.row]
    Cell.dateFeedCellLabel.text = "test"
    Cell.likeCountFeedCellLabel.text = String(likeArray[indexPath.row])
    Cell.postImageFeedCellLabel.sd_setImage(with: URL(string: self.userPostImageArray[indexPath.row]))
    Cell.postDescriptionLabel.text = userPostDescription[indexPath.row]

    if userPostImageArray[indexPath.row] == ""{
        Cell.postImageFeedCellLabel.isHidden = true
    }

    if userPostImageArray[indexPath.row] != "" {
        Cell.postImageFeedCellLabel.isHidden = false
    }

    return Cell

//Cell.userProfilePhotoFeedCellLabel.sd_setImage(with: URL(string: self.userProfilePhotoArray[indexPath.row]))

如果我只注释掉配置文件单元格,那么我的应用程序会成功运行,但每当我添加它时它就会崩溃。

下面你可以看到我在哪里尝试确保我的 var userProfilePhotoArray 不会超出我的索引范围,因为我将它设置为等于一个变量以限制超出数组范围。

      if self.profilecount <= self.PosterEmail.count{

self.profilecount = self.profilecount + 1

       func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return PosterEmail.count
}      

    func getDatFromFirestore() {

let firestoreDatabase = Firestore.firestore()

    firestoreDatabase.collection("Posts").order(by: "Date" , descending : true).addSnapshotListener { (snapshot, error) in
        if error != nil {
            print(error?.localizedDescription ?? "Connection Error")
        } else {
            self.userPostImageArray.removeAll(keepingCapacity: false)
            self.userCommentArray.removeAll(keepingCapacity: false)
            self.userCommentArray.removeAll(keepingCapacity: false)
            self.likeArray.removeAll(keepingCapacity: false)
            self.PosterEmail.removeAll(keepingCapacity: false)
            self.userProfilePhotoArray.removeAll(keepingCapacity: false)

            for document in snapshot!.documents {

                self.dbread = self.dbread + 1

                print(self.dbread)

                let documentID = document.documentID

                self.documentIDArray.append(documentID)

                self.getUserProfilePhoto()

                if let postedBy = document.get("postedBy") as? String {

                    self.PosterEmail.append(postedBy)

                    let db = Firestore.firestore()

                    let docRef = db.collection("Public").document(postedBy)

                    docRef.getDocument { (document, error) in
                        if self.profilecount <= self.PosterEmail.count{
                        self.profilecount = self.profilecount + 1
                        print("Profile count is \(self.profilecount)")
                        if let document = document, document.exists {
                            print(document)
                            if let userProfile = document.get("imageUrl") as? String {

                                self.userProfilePhotoArray.append(userProfile)

                                print("time = \(Date.self), \(self.userProfilePhotoArray).")


                        }
                    }
                }
            }

                if let postDescription = document.get("PostDescription") as? String {
                    self.userPostDescription.append(postDescription)
                }

                if let imageUrl = document.get("imageUrl") as? String {
                    self.userPostImageArray.append(imageUrl)
                }

                if let PostLikes = document.get("Likes") as? Int {
                    self.likeArray.append(PostLikes)
                }

                if let timeStamp = document.get("Date") as? Date {

                    let formatter = DateFormatter()
                    formatter.dateFormat = "MM/dd/yyyy"
                    let dateString = formatter.string(from: timeStamp)

                    let timeStampAsString = dateString

                    self.postDate.append(timeStampAsString)
                }

            }
            self.VidaFeed.reloadData()
        }

    }
}

下面是输出,我可以清楚地看到该数组等于我的 PosterEmail 数组计数,并且它不会结束,但是每当为用户的个人资料图像重新添加单元格时,应用程序就会崩溃。

Posteremail count = 1
Profile count is 1
<FIRDocumentSnapshot: 0x6000001a2850>
time = 2020-06-01 03:00:28 +0000, "https://firebasestorage.googleapis.com/v0/b/vida-clock-11690.appspot.com/o/UserProfilePhotos%2F8C2ADEC6-C108-4C70-8CDA-ADBFCC56B4E2?alt=media&token=1c2178b8-b35b-4e2a-bbc0-c7747843b673"].

我只是被困住了,到目前为止,我已经厌倦了。有什么建议么?

标签: arraysswiftfirebasegoogle-cloud-firestore

解决方案


Firebase通过网络连接或本地磁盘缓存获取文档,这意味着无法保证每个 API 调用需要多长时间。因此,Firebase API调用始终是异步的。您的第一个 API 调用将获取Posts按日期排序的集合,遍历所有文档并将数据附加到PosterEmail数组中。它还将数据附加到userProfilePhotoArray数组中,但请注意,这是通过不同的 API 调用完成的,这意味着它是异步完成的。但是,您在第二个异步调用完成之前调用reloadData()方法VidaFeed- 填充的那个userProfilePhotoArray- 这意味着计数PosterEmail并不userProfilePhotoArray相同。

解决此问题的一种方法是在其中self.VidaFeed.reloadData()添加docRef.getDocument { (document, error) in ... }

        docRef.getDocument { (document, error) in
          if self.profilecount <= self.PosterEmail.count{
            self.profilecount = self.profilecount + 1
            print("Profile count is \(self.profilecount)")
            if let document = document, document.exists {
              print(document)
              if let userProfile = document.get("imageUrl") as? String {

                self.userProfilePhotoArray.append(userProfile)

                print("time = \(Date.self), \(self.userProfilePhotoArray).")

                // Add this line. 
                self.VidaFeed.reloadData()
              }
            }
          }
        }

这样可以确保VidaFeed每次将新项目添加到 时都会收到通知userProfilePhotoArray

现在,在cellForRowAt方法中,替换

Cell.userProfilePhotoFeedCellLabel.sd_setImage(with: URL(string: self.userProfilePhotoArray[indexPath.row]))

if indexPath.row < self.userProfilePhotoArray.count {
    Cell.userProfilePhotoFeedCellLabel.sd_setImage(with: URL(string: self.userProfilePhotoArray[indexPath.row]))
}

推荐阅读