【问题标题】:Xcode is saying my array is out of range but I can confirm that my array is not out of rangeXcode 说我的数组超出范围,但我可以确认我的数组没有超出范围
【发布时间】:2020-09-19 07:41:56
【问题描述】:

我有一个用于我的 TableView 单元的数组,类似于 Facebook 提要。我成功地让我的应用程序版本的 Feed 成功显示了用户发帖的日期、显示创建帖子的用户电子邮件、显示随帖子上传的照片,但我似乎不知道如何为他们的用户个人资料制作一个数组。所有信息均来自 Firebase。

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

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

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

Posts Database Struture


表格视图

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

Public > UserEmail (test@gmail.com) > 用户信息(姓名、日期、头像 url)

Public Database Structure

我通过获取 Firestore 数据库的信息来获取帖子信息,并将所有内容放入数组中。

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

//发布变量 var userCommentArray = 字符串

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"].

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

【问题讨论】:

    标签: arrays swift firebase google-cloud-firestore


    【解决方案1】:

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

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

            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()
                  }
                }
              }
            }
    

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

    现在,在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]))
    }
    

    【讨论】:

    • 完美!现在用户的个人资料照片正确显示了正确的用户个人资料照片。在对 Firestore 进行两次不同的调用时,我一定会重新加载数据以避免再次出现此问题。非常感谢。
    • @IrvingGonzalez 这是一个很好的答案,但只是一个澄清/更正; 这样可以确保每次将新项目添加到 userProfilePhotoArray 时都会通知 VidaFeed 此处不正确。 docRef.getDocument 只获取一次文档,因此 vidaFeed 只会在调用该函数时更新,而不是在添加新项目时更新。在父集合上使用addSnapshotListener 将确保在添加新项目时刷新 tableView。否则投赞成票。
    猜你喜欢
    • 2023-04-10
    • 2022-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-19
    • 1970-01-01
    • 2015-02-04
    相关资源
    最近更新 更多