点击节标题时如何动态将数据添加到UITableView

时间:2018-09-19 07:08:28

标签: ios swift tableview uitableviewsectionheader

我面临着将数据动态加载到UITableView节中的问题。我的业务需求是我有一个名为“课程”的ViewController,在此视图中,我有一个tableView,其中我使用了TableViewHeaderFooterView的不同部分,每个标题都有相关的课程名称,该课程中的章节数量以及该课程的作业数量,我从API调用中获取所有这些数据,我可以使用此数据填充tableView标头,并且我还将获得一个'id'对于我添加为每个标题的标签的每个课程。现在,当我点击任意一个标头时,我必须通过发送标头的tag值(即courseID)进行另一个API调用,因此我将获得tableView的数据源,并且应该使用显示行和数据的方式扩展该部分在数据源的行中。

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

我试图这样做,当我第一次单击任何标题时,它正在显示该部分的数据,但是如果再次单击相同的标题或任何其他标题,我会因< / p>

  

由于未捕获的异常“ 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)")
}

这就是我所拥有的,过去2天我一直在尝试此操作,我无法弄清楚。

3 个答案:

答案 0 :(得分:2)

您的表格视图的数据源不一致。每个部分都应该有自己的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
}

答案 1 :(得分:1)

您应该重新设计模型。 模型必须反映您的UI。由于节包含N行,因此您的节模型应具有Array的{​​{1}}。因此,您可以轻松地归档特定Row Model的行列表。在两个不同的Section中管理Section & Row令人头疼。

例如。

Array

现在您的struct SectionModel { var opened: Bool! var yourTableRowModels = [RowModel]() } struct RowModel { var someAttribute: String! } 方法中使用以下方法。

TableViewDataSource

答案 2 :(得分:0)

这是所有部分的行数。

尝试以下代码:

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

不需要:

tableView.beginUpdates()
tableView.endUpdates()

我猜在toggleSection中。

编辑

再尝试一种方法:

fun toggleSection中:

for courseNamesModel in sectionData {
    courseNamesModel.opened = false
}
sectionData[section].opened = !sectionData[section].opened

因为您必须将先前打开的标题设置为false。

相关问题