ios - 点击部分标题时如何将数据动态添加到 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)")
}
这就是我所拥有的,过去两天我一直在尝试这个,但我无法弄清楚。
解决方案
您的表视图的数据源不一致。每个部分都应该有自己的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
}
推荐阅读
- kentico - 启用文化时的奇怪 URL
- excel - 使用 VBA 在第一个块下剪切和粘贴数据块
- html - 为什么 SVG 不渲染
- vue.js - 如何使用 vuetify 使字体大小响应?
- angular - 为什么带有 @Inject 装饰器的注入属性不能作为 this.injected_property 使用
- c - 为什么我得到以下代码的分段错误?
- python - 将我排序的 pandas 数据帧迭代到 groupby 非常慢。有什么选择吗?
- java - 如何在 JTextField 中动态编写格式化文本,如粗体、斜体或使用项目符号和编号?
- haskell - Haskell 的 forkIO 的实现
- android - Android以编程方式自动更改文本颜色