【问题标题】:Swift Getting Index Out of Range Error While reading Data From Firestore从 Firestore 读取数据时 Swift 出现索引超出范围错误
【发布时间】:2021-03-28 09:42:15
【问题描述】:

我正在尝试从 Firestore 中提取图像数据并通过将图像添加到 tableView 单元格来更新 UI。

但是,我收到 Index out of Range 错误。我相信这是因为时间问题。

你能帮我解决这个问题吗?

提前致谢。

致命错误:索引超出范围:文件 Swift/ContiguousArrayBuffer.swift,第 444 行

    override func viewDidLoad() {
    super.viewDidLoad()
    
    createBubbleView()
    getDataFromFireStore()
    
    detailsTableView.delegate = self
    detailsTableView.dataSource = self

    // MARK: - NIB REGISTRATION
    detailsTableView.register(UINib(nibName: K.ingredientsNibName, bundle: nil), forCellReuseIdentifier: K.ingredientsCell)
    detailsTableView.register(UINib(nibName: K.stepsNibName, bundle: nil), forCellReuseIdentifier: K.stepsCell)
    detailsTableView.register(UINib(nibName: K.recipeNameNib, bundle: nil), forCellReuseIdentifier: K.recipeNameCell) }

    

  func getDataFromFireStore() {
    
    let db = Firestore.firestore()
for ingredient in ingredients {
        db.collection("Ingredients").whereField("name", isEqualTo: ingredient)
            .getDocuments() { [self] (querySnapshot, err) in
                if let err = err {
                    
                    print("Error getting documents: \(err)")
                } else {
                    for document in querySnapshot!.documents {
                        print(document.get("image")!)
                        if let imageURLsDB = document.get("image") as? [String] {

                            ingredientsImageURLs.append(document.get("image") as! String)
                            
                        }
                        
                        
                    }
            }
            }
    }
    

 // MARK: - RETURNS THE VALUE OF EACH CELL IN THE TABLEVIEW
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {


    let cell = detailsTableView.dequeueReusableCell(withIdentifier: K.ingredientsCell)
    switch indexPath.section {
    //        RECIPE NAME
    case 0:
        let cell = detailsTableView.dequeueReusableCell(withIdentifier: K.recipeNameCell) as! RecipeTitleCell
        cell.cookingTimeLabel.text = cookingTime
        cell.numberOfIngredientsLabel.text = String(ingredients.count)
        
        return cell
        
    //        INGREDIENTS
    case 1:
        let cell = detailsTableView.dequeueReusableCell(withIdentifier: K.ingredientsCell) as! IngredientsCell
        
        cell.ingredientName.text = ingredients[indexPath.row]
        
        cell.textLabel?.font = UIFont(name:"Mulish-regular", size:12)
        cell.textLabel?.numberOfLines = 0
        cell.textLabel?.lineBreakMode = NSLineBreakMode.byWordWrapping
        
        DispatchQueue.main.async {
            cell.ingredientImage.sd_setImage(with: URL(string: self.ingredientsImageURLs[indexPath.row]), placeholderImage: UIImage(systemName: "square.and.arrow.up"))
            self.detailsTableView.reloadData()
            
        }
        
        
        return cell

【问题讨论】:

  • 你在哪一行得到错误?行计数和节计数方法是什么样的?ingredientsingredientsImageURLs 数组如何保持同步?
  • @JoakimDanielson,当我尝试在成分图像单元格中显示图像时出现错误。您可以看到下面的行; cell.ingredientImage.sd_setImage(with: URL(string: self.ingredientsImageURLs[indexPath.row]), placeholderImage: UIImage(systemName: "square.and.arrow.up"))
  • 那么也许你也应该回答我的其他问题。
  • @JoakimDanielson,对不起。请在此处查看屏幕截图-drive.google.com/file/d/1q3md__tZ7tONUsH_e_H6G63SRFUXZQjw/…成分和成分ImageURLs 在firestore 中具有相同数量的元素。但是,当我调试时,我在成分ImageURLs 中看到 0 个元素
  • 我的猜测是在getDataFromFireStore函数中下载了部分(或全部)成分ImageURLs中的元素之前调用了发生崩溃的代码。避免这种情况的最佳方法可能是使用一个数组而不是两个数组。

标签: swift uitableview google-cloud-firestore swift5


【解决方案1】:
if let imageURLsDB = document.get("image") as? [String] {

   ingredientsImageURLs.append(document.get("image") as! String)
                        
}

您将 document.get("image") 检查为字符串数组,但是当您添加到数组时,您检查为字符串。

【讨论】:

  • 更新了,可惜没有解决。
  • 向成分添加数据时?
  • 它已经在数据库中了。它只是提取数据。
  • 请把viewcontroller的所有代码分享给我好吗?您可以添加到云端硬盘。
【解决方案2】:

您正在为图像调用后端,然后重新加载数据,所以它每次都调用,设置图像不停。不能在 cellForRow 中调用 reload data,因为它会重复调用 table view delegates。

private func getImages()
        DispatchQueue.main.async {
        cell.ingredientImage.sd_setImage(with: URL(string:self.ingredientsImageURLs[indexPath.row]), placeholderImage: UIImage(systemName: "square.and.arrow.up"))
        self.imageArray = imagesFromFireStore
        self.detailsTableView.reloadData()
    }

//你可以把代码放在这里

if let imageURLsDB = document.get("image") as? [String] {
                        ingredientsImageURLs.append(document.get("image") as! String)
      //       here just append images to array and call
      self.reloadData()
  }

在表格视图中使用你的 imageArray[indexPath.row]

【讨论】:

  • 你是对的。我更新了那个部分。但是,tableView cellForRow 在从 Firestore 中提取数据之前仍在执行。从 Firestore 准备好数据后,如何填充图像?
  • 在控制器中创建空的图像数组,而不是创建一个调用图像的函数,当数据到达您时填充数组,并在该函数调用中重新加载数据。我刚刚编辑了答案,当然你不会用索引路径行来调用它,用于每个或其他东西。
【解决方案3】:

谢谢大家的意见。我就是这样解决的。

  1. 在获得适量数据后将图像设置为单元格

    if ingredientsImageURLs.count ==  ingredients.count {
            cell.ingredientImage.sd_setImage(with: URL(string: self.ingredientsImageURLs[indexPath.row]), placeholderImage: UIImage(systemName: "square.and.arrow.up"))
        }
    
  2. 下载完所有图片后重新加载数据。

    func getDataFromFireStore() {

    let db = Firestore.firestore()
    
    let recipeDocRef = db.collection("Recipes").document(selectedRecipeID).addSnapshotListener { [self] (snapshot, error) in
    
        if let titleDB = snapshot?.get("title") as? String {
            self.recipeTitle = titleDB
            titleLabel.text = recipeTitle
        }
    
        if let ingredientsDB = snapshot?.get("ingredients") as? [String] {
            self.ingredients = ingredientsDB
        }
    
        if let cookingTimeDB = snapshot?.get("cookingTime") as? String {
            self.cookingTime = cookingTimeDB
        }
    
        if let imageUrlDB = snapshot?.get("imageUrl") as? String {
            self.imageUrl = imageUrlDB
            recipeImageView.sd_setImage(with: URL(string: imageUrl), placeholderImage: UIImage(systemName: "square.and.arrow.up"))
    
        }
    
        if let cookingStepsDB = snapshot?.get("cookingSteps") as? [String] {
            self.steps = cookingStepsDB
        }
    
        if let stepImagesDB = snapshot?.get("stepImages")  as? [String]{
            self.stepsImages = stepImagesDB
        }
    
        for ingredient in self.ingredients {
            db.collection("Ingredients").whereField("name", isEqualTo: ingredient)
                .getDocuments()
                { [self] (querySnapshot, err) in
                    if let err = err {
    
                        print("Error getting documents: \(err)")
                    } else {
                        for document in querySnapshot!.documents {
                            ingredientsImageURLs.append(document.get("image") as! String)
                        }
                        self.detailsTableView.reloadData()
    
                    }
                }
            self.detailsTableView.reloadData()
        }
    
    }
    

    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-14
    • 1970-01-01
    • 1970-01-01
    • 2020-06-22
    • 1970-01-01
    • 1970-01-01
    • 2019-06-17
    相关资源
    最近更新 更多