UICollectionView 给出“索引超出范围”错误

Posted

技术标签:

【中文标题】UICollectionView 给出“索引超出范围”错误【英文标题】:UICollectionView gives "Index out of range" error 【发布时间】:2018-10-28 12:08:43 【问题描述】:

这是一个问题。目前我想在 UITableView 中显示在数据库中注册的用户数的 UITableViewCell 。但是,它在 UITableViewDataSOurce 方法 (cellForItemAt) 中变为“索引超出范围”。 我理解错误的含义,但我不知道为什么会出现这样的错误。你能告诉我吗?

import UIKit
import Firebase
import FirebaseStorage
import FirebaseFirestore
import SDWebImage

struct MemberData 
  var image: URL?
  var text: String?


class MemberSelectViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout 
  let statusBsr = UIApplication.shared.statusBarFrame.height

  let db = Firestore.firestore()
  var teamIDFromFirebase: String = ""
  var fireAuthUID = (Auth.auth().currentUser?.uid ?? "no data")
  var memberData = [MemberData]()

  var memberImageArr = [Any]()
  var memberTextArr = [Any]()
  var memberUserIDArr = [Any]()

  override func viewDidLoad() 
      super.viewDidLoad()

      let collectionView = UICollectionView(frame: CGRect(x: 0, y: statusBsr, width: self.view.frame.width, height: self.view.frame.size.height - statusBsr), collectionViewLayout: UICollectionViewFlowLayout())

      let nibName = UINib(nibName: "memberCollectionViewCell", bundle: nil)
      collectionView.register(nibName, forCellWithReuseIdentifier: "memberCell")

      collectionView.delegate = self
      collectionView.dataSource = self

      self.view.addSubview(collectionView)
      getMemberData(collectionView: collectionView)
  

  func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int 
      return 24
  

  func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize 
      let size = self.view.frame.size.width / 4
      return CGSize(width: size, height: size)
  

  func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets 

      let inset =  (self.view.frame.width / 4) / 5

      return UIEdgeInsets(top: inset, left: inset, bottom: inset, right: inset)
  

  func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat 
      return (self.view.frame.width / 4) / 5
  

  func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
      let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "memberCell", for: indexPath) as! memberCollectionViewCell
          let cellData = memberData[indexPath.row]
          cell.memberImage.sd_setImage(with: cellData.image)
          cell.memberTitle.text = cellData.text
      return cell
  



private extension MemberSelectViewController 
    private func getMemberData(collectionView: UICollectionView) 
    self.db.collection("users").document(self.fireAuthUID).addSnapshotListener  (snapshot3, error) in
        guard let document3 = snapshot3 else 
            print("erorr2 \(String(describing: error))")
            return
        
        guard let data = document3.data() else  return 
        self.teamIDFromFirebase = data["teamID"] as? String ?? ""
        self.db.collection("users").whereField("teamID", isEqualTo: self.teamIDFromFirebase).getDocuments()  (querySnapshot, err) in
            if let err = err 
                print("Error getting documents: \(err)")
                return
             else 
                var i = 0
                for document in querySnapshot!.documents 
                    guard var documentData: [String: Any] = document.data() else  return 
                    self.memberImageArr.append((documentData["image"] as? String)!)
                    self.memberTextArr.append((documentData["name"] as? String)!)
                    self.memberData.append(MemberData(image: URL(string: self.memberImageArr[i] as! String), text: self.memberTextArr[i] as! String))
                    i += 1
                
            
        
    


【问题讨论】:

发布完整的日志,可能代码没有执行self.memberData.append() let cellData = memberData [indexPath.row] ⇨ 线程1:致命错误:出现索引超出范围。 【参考方案1】:

在这个方法中

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int 
  return 24

您通知集合视图将始终有 24 行,因此当视图加载时,它将开始在集合视图中获取 24 行的内容。

但是,您的 memberData 数组是这样定义的:

var memberData = [MemberData]()

意味着最初它是空的。

然后您开始在getMemberData 中向memberData 添加内容,但此时,您的集合视图可能已经开始填充并正在请求第 5 行的内容(例如)...在一个数组中没有元素,那会崩溃。

所以你可以做的是:

    numberOfItemsInSection 更改为返回静态值,而是返回memberData 中的实际项目数,如下所示:

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int 
        return memberData.count
    
    

    getMemberData 函数中将数据加载到memberData 后,您会告诉集合视图重新加载,它会再次运行构建集合视图的整个过程,这次是数据。

    cellForItemAt 中,您可以确保不要尝试获取不存在的内容:

    if indexPath.row < memberData.count 
        let cellData = memberData[indexPath.row
        //and so on
    
    

希望能给你一些线索。

【讨论】:

以上是关于UICollectionView 给出“索引超出范围”错误的主要内容,如果未能解决你的问题,请参考以下文章

monotouch UICollectionView 给出空引用错误

UICollectionView reloadData后cell被隐藏

二级的uicollectionview怎么实现

UICollectionView didSelectItemAt 方法不起作用

Swift UICollectionView 单元格过渡效果

使用 Parse 数据库的 UICollectionView 问题