首页 > 解决方案 > 点击部分标题时如何将数据动态添加到 UITableView

问题描述

我面临UITableView动态将数据加载到部分的问题。我的业务需求是我有一个ViewController名为“课程”,在这个视图中,我有一个tableView不同的部分,我使用了不同的部分TableViewHeaderFooterView,对于每个标题,它都有相关的课程名称、该课程中的章节数和该课程的作业数我从 API 调用中获取所有这些数据我能够tableView用这些数据填充标题,而且我将为每个课程获得一个“id”,我将其添加为每个标题的标签。现在,当我点击任何标题时,我必须通过发送标题的标签值来进行另一个 API 调用,即 courseID,

在点击标题之前,我可以使用我拥有数据源的静态数据来完成所有这些操作,但是如果要在点击标题时动态添加数据,我不知道该怎么做。

我试图这样做,当我第一次单击任何标题时,它会显示该部分的数据,但是如果我再次单击相同的标题或任何其他标题,我就会崩溃

由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因:“无效更新:第 0 节中的行数无效。更新 (0) 后现有节中包含的行数必须等于该节中包含的行数更新前的节 (1),加上或减去从该节插入或删除的行数(0 插入,0 删除),加上或减去移入或移出该节的行数(0 移入,0 移动出去)。

我在这里发布我的模型和代码:

课程名称模型:

struct CourseNamesModel {

var courseName: String!
var courseNameLetter: String!
var numberOfChaptersAndAssignments: String!
var chapterCount: Int!
var courseId: Int!
var opened: Bool!

init(courseName: String, courseNameLetter: String, numberOfChaptersAndAssignments: String, chapterCount: Int, courseId: Int ,opened: Bool) {

    self.courseName = courseName
    self.courseNameLetter = courseNameLetter
    self.numberOfChaptersAndAssignments  = numberOfChaptersAndAssignments
    self.chapterCount = chapterCount
    self.courseId = courseId
    self.opened = opened
  }
}

点击标题后的数据模型:

struct CourseDataModel {

var chapterName: String!
var documentAndAssignmentCount: String!

init(chapterName: String, documentAndAssignmentCount: String!) {

    self.chapterName = chapterName
    self.documentAndAssignmentCount = documentAndAssignmentCount
  }
}

我的 viewController 和 TableView 的代码

import UIKit
import Alamofire

class CoursesViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, ExpandableHeaderViewDelegate {

@IBOutlet weak var tableView: UITableView!
var sectionData = [CourseNamesModel]()
var tableData = [CourseDataModel]()

var selectedIdexPath: IndexPath!
override func viewDidLoad() {
    super.viewDidLoad()

    self.setFontFamilyAndSize()
    self.title = "Courses"
    selectedIdexPath = IndexPath(row: -1, section: -1)
    tableView.register(UINib(nibName: "ExpandableHeaderView", bundle: nil), forHeaderFooterViewReuseIdentifier: "expandableHeaderView")
   getCourseNames()
}

func numberOfSections(in tableView: UITableView) -> Int {
    return sectionData.count
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return tableData.count
}

func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    return tableView.frame.size.height/8.2
}

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {

    if sectionData[indexPath.section].opened {
        return tableView.frame.size.height/8.48275862069
    } else {
        return 0
    }
}

func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {

    return 1
}

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "expandableHeaderView") as! ExpandableHeaderView
    headerView.customInit(courseName: sectionData[section].courseName, letterSign: sectionData[section].courseNameLetter, numberOfChaptersAndAssignments: sectionData[section].numberOfChaptersAndAssignments, section: section, delegate: self)
    headerView.tag = sectionData[section].courseId
    return headerView
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "dataCell") as! DataCell
    cell.chapterName.text = tableData[indexPath.row].chapterName
    cell.numberOfDocumentsAndAssignments.text = tableData[indexPath.row].documentAndAssignmentCount
    return cell
}

func getCourseNames() {

    sectionData = []

    let courseNamesURL = "\(WebAPI.baseURL2 + WebAPI.coursesAPI)"

    Alamofire.request(courseNamesURL, method: .get, parameters: nil, encoding: JSONEncoding.default, headers: nil).responseJSON { response in

        switch response.result {
        case .success:

            let responseData = response.result.value as? [[String: Any]]
            guard let courseNamesData = responseData else {return}

            for courseDetail in courseNamesData {
                let courseName = courseDetail["CourseName"] as! String
                let courseNameLetter = String(courseName.first!)
                let chaptersCount = courseDetail["Chapterscount"] as! Int
                let assignmentsCount = courseDetail["AssignmentCount"] as! Int
                let chaptersAndAssignemntsCount = "\(chaptersCount) Chapters, \(assignmentsCount) Assignments"
                let courseId = courseDetail["CourseId"] as! Int
                self.sectionData.append(CourseNamesModel(courseName: courseName, courseNameLetter: courseNameLetter, numberOfChaptersAndAssignments: chaptersAndAssignemntsCount, chapterCount: chaptersCount, courseId: courseId, opened: false))
            }
            DispatchQueue.main.async {
                self.tableView.reloadData()
            }
        case .failure(let error):
            print(error.localizedDescription)
        }
     }
   }
}

toggleSection(expand/Collapse) 委托函数的代码:

func toggleSection(header: ExpandableHeaderView, section: Int) {
    sectionData[section].opened = !sectionData[section].opened
    tableData = []
    let courseChaptersURL = "\(WebAPI.baseURL2 + WebAPI.courseChaptersAPI)\(header.tag)"
    Alamofire.request(courseChaptersURL, method: .get, parameters: nil, encoding: JSONEncoding.default, headers: nil).responseJSON {response in

        switch response.result {
        case .success:

            let responseData = response.result.value as? [[String : Any]]
            guard let courseChaptersData = responseData else {return}

            for chapterDetail in courseChaptersData {
                let chapterName = chapterDetail["ChapterName"] as! String
                let documentsCount = chapterDetail["Documentscount"] as! Int
                let assignmentsCount = chapterDetail["AssignmentCount"] as! Int
                let documentsAndAssignmentsCount = "\(documentsCount) Documents, \(assignmentsCount) Assignments"
                //                        let isMaterialPathDelete = chapterDetail["IsDeleteMaterialPath"] as! Bool
                self.tableData.append(CourseDataModel(chapterName: chapterName, documentAndAssignmentCount: documentsAndAssignmentsCount))
            }
            print(self.tableData.count)
        case .failure(let error):
            print(error.localizedDescription)
        }
        DispatchQueue.main.async {
            self.tableView.reloadData()
        }
    }
    tableView.beginUpdates()
    tableView.endUpdates()
    print("Selected Section Index is : \(section)")
}

这就是我所拥有的,过去两天我一直在尝试这个,但我无法弄清楚。

标签: iosswifttableviewuitableviewsectionheader

解决方案


您的表视图的数据源不一致。每个部分都应该有自己的var tableData = [CourseDataModel](),所以nubmerOfRowsInSection你应该有:

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return sectionData[section].tableData.count
}

始终更新主队列上的数据源。在调用之前做它reloadData,所以它应该看起来像:

DispatchQueue.main.async {
    self.sectionData.append...
    // or self.tableData.append...
    self.tableView.reloadData()
    // or reload section
}

推荐阅读