Ios 当每个部分的行数不同时,如何获取numberOfRows的计数?
我试图用XML文件中的条目填充tableview。到目前为止,我已经将XML文件解析为一个结构,并编写了titleForHeaderInSection和numberOfSections的方法,但我正在努力通过计算每个Ios 当每个部分的行数不同时,如何获取numberOfRows的计数?,ios,swift,uitableview,Ios,Swift,Uitableview,我试图用XML文件中的条目填充tableview。到目前为止,我已经将XML文件解析为一个结构,并编写了titleForHeaderInSection和numberOfSections的方法,但我正在努力通过计算每个中的条目来计算每个节的numberOfRows。我认为我的主要困难来自不理解如何使用[部分]。以下是我迄今为止所做的工作: 我解析了一个xml文件,该文件包含如下日历日期和事件。您将看到第一个calendarevent如何有2个假日和描述条目,而第二个有1个: <calenda
中的
条目来计算每个节的numberOfRows。我认为我的主要困难来自不理解如何使用[部分]。以下是我迄今为止所做的工作:
我解析了一个xml文件,该文件包含如下日历日期和事件。您将看到第一个calendarevent如何有2个假日和描述条目,而第二个有1个:
<calendar>
<calendarevent>
<month>October</month>
<dateevent>2018 10 01</dateevent>
<datenumber>01</datenumber>
<holiday>First Holiday</holiday>
<description>aaaaaaaaaa</description>
<holiday>Second Holiday</holiday>
<description>bbbbbbbbbb</description>
</calendarevent>
<calendarevent>
<month>October</month>
<dateevent>2018 10 10</dateevent>
<datenumber>10</datenumber>
<holiday>Third Holiday</holiday>
<description>ccccccccccc</description>
</calendarevent>
.... and so on
以下是我的XML解析器代码:
class CalendarViewController {
var myCalendarDatesFromStrut = [CalendarDates]()
var myCalendarEventsFromStrut = [CalendarDates.CalendarEvents]()
}
extension CalendarViewController {
func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
calendarEventsElementFromXML = elementName
}
func parser(_ parser: XMLParser, foundCharacters string: String) {
let data = string.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
if data.count != 0 {
switch calendarEventsElementFromXML
{
case "month": monthsFromXML = data
case "dateevent": eventdatesFromXML = data
case "datenumber": eventdatenumbersFromXML = data
case "holiday": holidaysFromXML = data
default: break
}
}
}
func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
if elementName == "calendarevent" {
var myCalendarDates = CalendarDates.CalendarEvents()
myCalendarDates.month = monthsFromXML
myCalendarDates.eventdate = eventdatesFromXML
myCalendarDates.eventdatenumber = eventdatenumbersFromXML
myCalendarDates.holiday = holidaysFromXML
myCalendarEventsFromStrut.append(myCalendarDates)
}
}
}
因此,在解析XML并将其附加到结构之后,我开始获取tableview的值
如果
与当前日期月相同,则每个部分由一个
组成。XML有其他月份的
,所以我不想要所有的。我检查XML中的当前月份是否为==月份,如果是,则计算numberOfSections的dateevents数,并将dateevents格式化为这些节的标题
然后,节中的每一行在相应的
中表示一个
首先,XML可能在一个
calendarevent
中包含多个holiday
元素,因此您需要更新CalendarEvents
以能够容纳多个假日
struct Holiday {
var title: String = ""
var description: String = ""
}
//You should better avoid plural form for something which represents a single object
struct CalendarEvent {
var month: String = ""
var eventdate: String = ""
var eventdatenumber: String = ""
//Better use plural form for the name representing multiple objects
var holidays: [Holiday] = []
}
(我删除了外部结构CalendarDates,因为我找不到任何需要嵌套类型的原因。此外,我建议您避免使用复数形式来命名表示单个对象的对象。)
要使用结构解析XML,需要在
XMLParserDelegate
中使用更多属性:
class CalendarViewController: UIViewController {
//`myCalendarEventsFromStrut` is too long and `FromStrut` does not make sense
var myCalendarEvents: [CalendarEvent] = []
//Properties needed for parsing your XML
var textCurrentlyParsed: String? = nil
var monthFromXML: String = ""
var dateeventFromXML: String = ""
var datenumberFromXML: String = ""
var holidaysFromXML: [Holiday] = []
//Your table view shows some selected evnets in `myCalendarEvents`,
//To improve response, you should beter keep the filtered result, when `selectedDate` is updated.
var selectedDate: Date? {
didSet {
if let date = selectedDate {
let currentMonthShown = monthFormatter.string(from: date)
allEventsInVisibleMonth = myCalendarEvents.filter({ $0.month == currentMonthShown })
} else {
allEventsInVisibleMonth = [] //Or you prefer `allEventsInVisibleMonth = myCalendarEvents`?
}
}
}
var allEventsInVisibleMonth: [CalendarEvent] = []
//You may have this sort of constants somewhere, this is just an example
let TheCellID = "cell" //Change this according to your actual setups
//
// Date formatters.
// Better keep distinct DateFormaters accoding to the format to avoid simple mistakes
//
let monthFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "MMMM"
return formatter
}()
let dateeventFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "yyyy MM dd"
return formatter
}()
let sectionHeaderFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "yyyy-MM-dd"
return formatter
}()
//...
}
(上面的代码添加了一些内容来编写UITableViewDataSource
方法的示例。)
使用上述属性,您可以编写XMLParserDelegate
方法,如下所示:
extension CalendarViewController: XMLParserDelegate {
func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
switch elementName {
case "month", "dateevent", "datenumber", "holiday", "description":
//Reset the text content for the element
textCurrentlyParsed = ""
case "calendarevent":
//Reset all variables which may contain the result of previous element
monthFromXML = ""
dateeventFromXML = ""
datenumberFromXML = ""
holidaysFromXML = []
case "calendar":
//Can be ignored
break
default:
print("Unexpected start tag:", elementName)
break
}
}
func parser(_ parser: XMLParser, foundCharacters string: String) {
//`parser(_:foundCharacters:)` may be called several times for a seemingly single text content,
//So you need to add the `string` to the currently parsed text
textCurrentlyParsed? += string
}
func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
switch elementName {
case "calendarevent":
var calendarEvent = CalendarEvent()
calendarEvent.month = monthFromXML
calendarEvent.eventdate = dateeventFromXML
calendarEvent.eventdatenumber = datenumberFromXML
calendarEvent.holidays = holidaysFromXML
myCalendarEvents.append(calendarEvent)
case "month":
if let parsedText = textCurrentlyParsed?.trimmingCharacters(in: .whitespacesAndNewlines) {
monthFromXML = parsedText
}
case "dateevent":
if let parsedText = textCurrentlyParsed?.trimmingCharacters(in: .whitespacesAndNewlines) {
dateeventFromXML = parsedText
}
case "datenumber":
if let parsedText = textCurrentlyParsed?.trimmingCharacters(in: .whitespacesAndNewlines) {
datenumberFromXML = parsedText
}
case "holiday":
if let parsedText = textCurrentlyParsed?.trimmingCharacters(in: .whitespacesAndNewlines) {
var holiday = Holiday()
holiday.title = parsedText
holidaysFromXML.append(holiday)
}
break
case "description":
if
let parsedText = textCurrentlyParsed?.trimmingCharacters(in: .whitespacesAndNewlines),
case let lastIndexOfHoliday = holidaysFromXML.count - 1, lastIndexOfHoliday >= 0
{
//You need to modify the last entry in `holidaysFromXML`
holidaysFromXML[lastIndexOfHoliday].description = parsedText
}
default:
print("Unexpected end tag:", elementName)
break
}
}
}
(如果您不需要对文本进行修剪
,则可以稍微简化上面的代码。)
包含这些代码后,您的
UITableViewDataSource
方法将如下所示:
struct CalendarDates {
struct CalendarEvents {
var month = ""
var eventdate = ""
var eventdatenumber = ""
var holiday = ""
var description = ""
}
}
extension CalendarViewController: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return allEventsInVisibleMonth.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return allEventsInVisibleMonth[section].holidays.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let eventForTheSection = allEventsInVisibleMonth[indexPath.section]
let holidayForTheRow = eventForTheSection.holidays[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: TheCellID, for: indexPath)
//... setup the cell using `eventForTheSection` and `holidayForTheRow`
return cell
}
// Prints <dateevent> reformatted as section header
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let eventForTheSection = allEventsInVisibleMonth[section]
if let eventdateAsDate = dateeventFormatter.date(from: eventForTheSection.eventdate) {
return sectionHeaderFormatter.string(from: eventdateAsDate)
} else {
return "Broken eventdate: \(eventForTheSection.eventdate)"
}
}
}
扩展日历视图控制器:UITableViewDelegate,UITableViewDataSource{
func numberOfSections(在tableView:UITableView中)->Int{
返回allEventsInVisibleMonth.count
}
func tableView(tableView:UITableView,numberofrowsinssection:Int)->Int{
返回allEventsInVisibleMonth[节].holidays.count
}
func tableView(tableView:UITableView,cellForRowAt indexath:indexPath)->UITableViewCell{
让eventForTheSection=allEventsInVisibleMonth[indexPath.section]
让holidayForTheRow=eventForTheSection.holidays[indexPath.row]
let cell=tableView.dequeueReusableCell(标识符:TheCellID,for:indexath)
//…使用'eventForTheSection'和'holidayForTheRow'设置单元格`
返回单元
}
//打印重新格式化为节标题的内容
func tableView(tableView:UITableView,titleForHeaderInSection:Int)->String{
让eventForTheSection=AllEventsVisiblemon[节]
如果让eventdateAsDate=dateeventFormatter.date(发件人:eventForTheSection.eventdate){
返回节HeadPerformatter.string(from:eventdateAsDate)
}否则{
返回“断开的eventdate:\(节的eventForTheSection.eventdate)”
}
}
}
(未测试,您可能需要一些修复。)
通常,UITableViewDataSource
方法可以经常调用,因此您应该高效地实现它们
因此,不建议在每次调用时创建筛选数组。
您最好仅在以下情况下更新allEventsInVisibleMonth
:
已更新(不包括在上述我的代码中)myCalendarEvents
已更新(selectedDate
中的selectedDate
将执行此操作)didSet
有点长,但我认为值得一试。您的
部分似乎没有明确定义。你想在每个部分展示什么?在当前的numberOfSections(In:)
中,返回特定月份的日历事件数。这意味着每个部分包含一个日历事件,这真的是你想要的吗?请澄清您希望在每个部分中显示的内容。在numberOfSections中,我检查是否与当前日期月相同,然后查找并显示与当前月份相同的部分。然后,我为各部分创建标题。对于numberOfRows,我想获得每个行的#of,并显示该行的#。所以在示例XML中,我有两个条目,所以我想要两行@OOPerOk,有些事情已经弄清楚了:每个部分由一个组成/一个部分中的每一行代表对应的一个,对吗?@OOPer是的,就是这样。我使用的是计算numOfsection,因为我只需要获取当前月份的月份,而不是所有包含其他月份的条目的月份。是的,节中的每一行代表对应的每一行中的一行,那么您可能需要更改CalendarEvents
的定义,因为它只能容纳一个假日,还需要对XMLParserDelegate
方法进行大量更新。你最好在你的问题中包括我上面写的两件事。有人会比我回答得更快,给出了一些明确的定义。这非常有帮助,尤其是解释。非常感谢你!我个人理解的一个问题是:在XML解析中,我看到一行代码是“case let lastIndexOfHoliday=holidaysFromXML.count-1,lastIndexOfHoliday>=0”。我真的不明白那是什么意思?我知道你是如何先解析日历事件,然后解析假日的。在CalendarEvents中,您似乎不检查是否有最后一个条目,但在假日中您会检查吗?第二个问题:我想
extension CalendarViewController: XMLParserDelegate {
func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
switch elementName {
case "month", "dateevent", "datenumber", "holiday", "description":
//Reset the text content for the element
textCurrentlyParsed = ""
case "calendarevent":
//Reset all variables which may contain the result of previous element
monthFromXML = ""
dateeventFromXML = ""
datenumberFromXML = ""
holidaysFromXML = []
case "calendar":
//Can be ignored
break
default:
print("Unexpected start tag:", elementName)
break
}
}
func parser(_ parser: XMLParser, foundCharacters string: String) {
//`parser(_:foundCharacters:)` may be called several times for a seemingly single text content,
//So you need to add the `string` to the currently parsed text
textCurrentlyParsed? += string
}
func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
switch elementName {
case "calendarevent":
var calendarEvent = CalendarEvent()
calendarEvent.month = monthFromXML
calendarEvent.eventdate = dateeventFromXML
calendarEvent.eventdatenumber = datenumberFromXML
calendarEvent.holidays = holidaysFromXML
myCalendarEvents.append(calendarEvent)
case "month":
if let parsedText = textCurrentlyParsed?.trimmingCharacters(in: .whitespacesAndNewlines) {
monthFromXML = parsedText
}
case "dateevent":
if let parsedText = textCurrentlyParsed?.trimmingCharacters(in: .whitespacesAndNewlines) {
dateeventFromXML = parsedText
}
case "datenumber":
if let parsedText = textCurrentlyParsed?.trimmingCharacters(in: .whitespacesAndNewlines) {
datenumberFromXML = parsedText
}
case "holiday":
if let parsedText = textCurrentlyParsed?.trimmingCharacters(in: .whitespacesAndNewlines) {
var holiday = Holiday()
holiday.title = parsedText
holidaysFromXML.append(holiday)
}
break
case "description":
if
let parsedText = textCurrentlyParsed?.trimmingCharacters(in: .whitespacesAndNewlines),
case let lastIndexOfHoliday = holidaysFromXML.count - 1, lastIndexOfHoliday >= 0
{
//You need to modify the last entry in `holidaysFromXML`
holidaysFromXML[lastIndexOfHoliday].description = parsedText
}
default:
print("Unexpected end tag:", elementName)
break
}
}
}
extension CalendarViewController: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return allEventsInVisibleMonth.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return allEventsInVisibleMonth[section].holidays.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let eventForTheSection = allEventsInVisibleMonth[indexPath.section]
let holidayForTheRow = eventForTheSection.holidays[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: TheCellID, for: indexPath)
//... setup the cell using `eventForTheSection` and `holidayForTheRow`
return cell
}
// Prints <dateevent> reformatted as section header
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let eventForTheSection = allEventsInVisibleMonth[section]
if let eventdateAsDate = dateeventFormatter.date(from: eventForTheSection.eventdate) {
return sectionHeaderFormatter.string(from: eventdateAsDate)
} else {
return "Broken eventdate: \(eventForTheSection.eventdate)"
}
}
}