【问题标题】:SWIFT Thread 1: Fatal error: Index out of range: Sections & RowsSWIFT Thread 1:致命错误:索引超出范围:部分和行
【发布时间】:2019-06-09 13:55:31
【问题描述】:

需要一些帮助来获得分组行以填充它们各自的部分。我让它工作了一秒钟,但试图调整代码以消除重复和丢失的行。从那以后,我一直在收到“致命错误”

这是一个练习项目。按部门分组的用户目录。使用 Firebase 拉取用户列表。按部门对它们进行分组,然后填充一个表格。

//MARK: - CELLS
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "directoryCell", for: indexPath) as! TableViewCell

    let departmentSections = Dictionary(grouping: directoryArray) { (user) -> String in
        return user.department
    }

    //ROW & SECTION SETUP
    let rowsInSection = Array(departmentSections.values)
    //let usersInRowData = rowsInSection[indexPath.section]
    let users = rowsInSection[indexPath.section][indexPath.row]

    //USER CELL INFO
    let profilePic = users.profilePic // PROFILE PHOTO GET AND DISPLAY
    let url = URL(string: profilePic); URLSession.shared.dataTask(with: url!, completionHandler: { (data, response, error) in
        if error != nil {
            print(error!)
            return
        }
        DispatchQueue.main.async {
            cell.profilePicView.image = UIImage(data: data!)
            cell.layoutSubviews()
        }
    }).resume()

    //CELL LABELS
    cell.displayNameLabel.text = users.displayName
    cell.emailLabel.text =       users.email
    cell.officeLabel.text =      users.office
    cell.titleLabel.text =       users.title
    cell.profilePicView.layer.masksToBounds = true;
    //cell.profilePicView.contentMode = UIView.ContentMode.scaleAspectFill;
    //cell.departmentLabel.text = users.department
    //cell.reportsToLabel.text = users.directReports
    //cell.extLabel.text = users.ext

    cell.layoutSubviews()

    return cell
}

我希望用户按部门分组。我得到的只是:“线程 1:致命错误:索引超出范围”

【问题讨论】:

    标签: swift swift5


    【解决方案1】:

    几点:

    表格视图或集合视图应显示数据数组(一维或二维)。字典是无序的,因此不适合两者的数据模型。

    您当前的代码在每次通过 cellForRowAt 时都会对您的数据模型进行计算密集型重建。您正在使用Dictionary(grouping:) 构建一个字典,然后在每个 通过tableView(_:cellForRowAt:) 时从这些字典中创建数组。而且您是通过首先创建字典来完成的,因此每个部分的顺序可能每次都不同。不要那样做。 (这可能是您崩溃的原因,因为在每次通过 `tableView(_:cellForRowAt:) 时,您的部门数组的顺序可能不同,因此每个部分中的用户数量可能不同。

    此外,在tableView(_:cellForRowAt:) 中构建数据模型没有任何意义,因为系统首先调用numberOfSections(in:),然后调用tableView(_:numberOfRowsInSection:),然后开始调用部分标题和单元格。您没有显示您的 numberOfSections(in:)tableView(_:numberOfRowsInSection:) 方法,但我看不出它们如何返回正确的信息,因为它们的数据模型在首次调用时未设置。

    我建议定义一个节结构数组,并在您第一次设置表格视图时填充它。

    struct SectionStruct: {
      let sectionTitle: String //Department name?
      let sectionItems: [User]
    }
    
    var sections = [SectionStruct]() //populate this as described below
    

    然后,当您第一次设置表格视图时,按部门名称对用户数组进行分组,构建一个部分结构数组,对该数组进行排序,并将其用作您的数据模型。

    现在在您的 numberOfSections 方法中将返回 sections.count

    rowsInSection 将返回 sections[section].count

    您可以将用于构建数据模型的代码放在 didSet 方法中,用于您的 directoryArray

    var directoryArray: [User] {
      didSet {
        //Code to group your users by department, build the section structures, and sort them
    
        tableView?.reloadData()  //Tell the table view to reload
      }
    

    注意:上述代码更像是伪代码,而不是您可以复制到项目中的实际代码。它旨在为您指明正确的方向。不要试图将它复制到您的项目中并在(何时)它无法编译时抱怨。

    如果您需要更多帮助来重构您的代码,您将不得不发布您的数据结构(例如您的directoryArray 的类型)以及您的numberOfSections(in:)tableView(_:numberOfRowsInSection:)tableView(_:titleForHeaderInSection:) 数据的代码源方法。编辑您的问题以在底部添加更改后的代码。不要尝试在 cmets 中发布代码。它未格式化,因此无法读取。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-08-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-28
      • 1970-01-01
      相关资源
      最近更新 更多