在获取数据期间索引超出部分中的行数范围

Posted

技术标签:

【中文标题】在获取数据期间索引超出部分中的行数范围【英文标题】:Index out of range in number of rows in section during fetching data 【发布时间】:2021-04-06 16:48:38 【问题描述】:

何时尝试使用我的表格视图和进度条打开新控制器时出现“索引超出范围”。 我从 Firestore 数据库中获取数据,想法是当我点击“下一步”按钮时,我想更新进度条并使用新值重新加载表视图。行数必须等于组数,但每个练习的组数不同,所以我想动态更改行数。

class StartViewController: UIViewController, UITableViewDelegate, UITableViewDataSource 

  var titleValue: String = ""
  var dayOfWorkout: String = ""
  var exerciseNumber = 0

  var models: [DataCell2] = []
  let user = Auth.auth().currentUser
  var db = Firestore.firestore()
    
  @IBOutlet weak var tableView: UITableView!
  @IBOutlet weak var exerciseLabel: UILabel!
  @IBOutlet weak var progressView: UIProgressView!


  override func viewDidLoad() 
     super.viewDidLoad()
       
     progressView.transform = progressView.transform.scaledBy(x: 1, y: 3)   
     tableView.delegate = self
     tableView.dataSource = self
     retrieveWorkouts()
  
    
  @IBAction func nextButtonPressed(_ sender: UIButton) 
        
     nextExercise()
        
     Timer.scheduledTimer(timeInterval: 0.2, target: self, selector: #selector(updateUI), userInfo: nil, repeats: false)
     tableView.reloadData()
  
    
  @objc func updateUI() 
     progressView.progress = getProgress() 
  
    
  func getProgress() -> Float 
     return Float(exerciseNumber) / Float(models.count)
  
    
  func nextExercise() 
        
     if exerciseNumber + 1 < models.count 
        exerciseNumber += 1
      else 
        exerciseNumber = 0
     
  

  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        
      **//HERE IS ERROR**  
      return models[exerciseNumber].sets!
  

以及从 Firestore 获取数据的方法

func retrieveWorkouts() 

   db.collection("users").document("\(user!.uid)").collection("WorkoutsName").document("\(titleValue)").collection("Exercises").order(by: "Number").getDocuments  (querySnapshot, error) in
      if let error = error
         print("\(error.localizedDescription)")
      else 
         if let snapshotDocuments = querySnapshot?.documents 
            for doc in snapshotDocuments 
                let data = doc.data()
                if let numberDb = data["Number"] as? Int, let exerciseDb = data["Exercise"] as? String, let kgDb = data["kg"] as? Int, let setsDb = data["Sets"] as? Int, let repsDb = data["Reps"] as? Int, let workoutName = data["workoutName"] as? String 
                    print("data is \(data)")
                    let newModel = DataCell2(Number: numberDb, Exercise: exerciseDb, kg: kgDb, sets: setsDb, reps: repsDb, workoutName: workoutName)
                    self.models.append(newModel)
                    self.tableView.reloadData()
                                   
             
          
       
    
 

【问题讨论】:

尝试在retrieveWorkouts方法内的主线程上调用reloadData。你确定nextExercise里面的逻辑吗?我认为您在其中切换了 if 和 else 条件。 不幸的是,主线程内的 reloadData 不起作用 您仍然应该这样做。你确定nextExercise 方法吗? 是的,我确定。唯一不起作用的是检索部分函数中的集合数为行数。 这有点跑题了,但你不会想在 for 循环 for doc in snapshotDocuments 内一遍又一遍地重新加载你的 tableView。之后移动重新加载,因此它只需在填充数据源后执行一次。 【参考方案1】:

您有时间问题。视图将在加载时尝试创建 tableView。此时模型数组将为空,因为异步 firebase 方法不会运行并更新它。但是你将executiveNumber初始化为0。

这意味着 numberOfRowsInSection 委托方法将尝试访问 models[0] 但由于此时数组为空,因此不存在并导致索引超出范围崩溃。

你可以通过一些防御性编程来解决这个问题:

  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        
      guard !model.isEmpty else return 0
      return models[exerciseNumber].sets!
  

您还可以添加第二个守卫或前提条件以确保executiveNumber

【讨论】:

【参考方案2】:

您基于行数 models[exerciseNumber].sets!

你正在设置锻炼号码

func nextExercise() 
        
     if exerciseNumber + 1 < models.count 
        exerciseNumber += 1
      else 
        exerciseNumber = 0
     
  

但是,这里有一个逻辑错误:您正在检查练习数是否小于 models.count,如果是,则增加它。这将导致exerciseNumber == models.count,并且由于数组是零索引的,这将超出数组的末尾并给出超出范围的错误。

一个简单的解决方法是将方法更改为:

func nextExercise() 
   exerciseNumber += 1
   if exerciseNumber == models.count 
      exerciseNumber = 0
   
   return exerciseNumber

有更聪明的方法可以做到这一点,但现在可以。

【讨论】:

不幸的是它仍然不起作用。但是我怀疑我在 nextExercise 中的逻辑是否不好,因为我从exerciseNumber = 0 开始,如果exerciseNumber 大于models.count 我增加,但是当exerciseNumber 将等于models.count 我的exerciseNumber 将再次为0,所以我从头开始,这里有什么问题? 我很抱歉 - 我误读为 if exercise &lt; model.count。在阅读然后剪切和粘贴时,我设法错过了+ 1 位。我的错!

以上是关于在获取数据期间索引超出部分中的行数范围的主要内容,如果未能解决你的问题,请参考以下文章

熊猫以时间为索引获取特定日期的行数

致命错误:追加数组时数组索引超出范围

试图获取超出范围索引 NaN 的框架(实时数据库)

java中poi怎么获取指定列的行数?

获取“索引超出数组范围”异常

如何根据uitableview中的部分获取索引路径?