首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >当每个节中的行数不同时,如何获得numberOfRows的计数?

当每个节中的行数不同时,如何获得numberOfRows的计数?
EN

Stack Overflow用户
提问于 2018-10-02 17:45:48
回答 1查看 133关注 0票数 1

我正在尝试用XML文件中的条目填充一个表视图。到目前为止,我已经将XML文件解析为Struct,并编写了用于titleForHeaderInSection和numberOfSections的方法,但是通过计算每个<calendarevent>中的<holiday>条目,正在艰难地计算每个节的numberOfRows。我认为我的主要斗争来自不理解如何使用部分。以下是我迄今所做的工作:

我分析了一个xml文件,它有这样的日历日期和事件。您将看到第一个日历如何有2个假日和描述条目,而第二个有1:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<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

到如下所示的结构:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct CalendarDates {
    struct CalendarEvents {
        var month = ""
        var eventdate = ""
        var eventdatenumber = ""
        var holiday = ""
        var description = ""
        }
}

以下是我的XML解析代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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并将其附加到结构后,我开始获取表视图的值。

如果<calendarevent>与当前日期月份相同,则每个区段由一个<month>组成。XML包含其他月份的<calendarevent>,所以我不想全部使用。我检查当前月份是否为XML中的==月,如果是,则为numberOfSections计数#日期事件,并将日期事件格式化为这些节的标题。

然后,节中的每一行表示对应<calendarevent>中的一个<calendarevent>

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
extension CalendarViewController: UITableViewDelegate, UITableViewDataSource {
    //Calculates # of <dateevents> in current month
    func numberOfSections(in tableView: UITableView) -> Int {
        formatter.dateFormat = "MMMM"
    let currentMonthShown = formatter.string(from: selectedDate)
    let allEventsInVisibleMonth = myCalendarEventsFromStrut.filter({ $0.month == currentMonthShown }).map {$0.eventdate}.count
    return allEventsInVisibleMonth
    }

    // Prints <dateevent> reformatted as section header
    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        formatter.dateFormat = "MMMM"
    let currentMonthShown = formatter.string(from: selectedDate)
    let allEventsInVisibleMonth = myCalendarEventsFromStrut.filter({ $0.month == currentMonthShown }).map {$0.eventdate}
    formatter.dateFormat = "yyyy-MM-dd"
    let eventStringsToDate = allEventsInVisibleMonth.map{ formatter.date(from: $0) }
    formatter.dateFormat = "yyyy-MM-dd"
    formatter.dateStyle = .long
    formatter.timeStyle = .none
    let eventDatesBackToString = eventStringsToDate.map{ formatter.string(from: $0 as! Date )}
    return eventDatesBackToString[section]
    }

现在,一节中的每一行都需要在相应的<holiday>中表示一个<calendarevent> --这是我陷入困境的地方。

对于tableview的numberOfRowsInSection,我需要计数<holiday>条目在每个<calendarevent>中的数量,并在每个节中显示该#行。然后打印in cellForRowAt。有人能给我一点提示吗?

这是我尝试过的,也是我具体失败的地方:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
     formatter.dateFormat = "MMMM"
     let currentMonthShown = formatter.string(from: selectedDate)
    let allEventsInMonth = myCalendarEventsFromStrut.filter({ $0.month == currentMonthShown }).map {$0.holiday}

    return allEventsInMonth.count //This gets me same number of rows in all sections = total # of events in current month.

//I'm struggling to figure out how to get # of events at a particular section, so I can make that the # of rows
    }
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-10-03 18:49:31

首先,XML可能在单个holiday中包含多个calendarevent元素,因此您需要更新您的CalendarEvents以便能够保存多个假期。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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中使用更多的属性。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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方法如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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
        }
    }
}

(如果您不需要对文本进行trim,那么上面的代码可以简化一些。)

在包含了这些代码之后,您的UITableViewDataSource方法将如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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)"
        }
    }

}

(没有测试,您可能需要一些修复。)

通常,可以经常调用UITableViewDataSource方法,因此您应该有效地实现它们。

因此,不建议在每次调用时创建筛选数组。最好只在以下情况下更新allEventsInVisibleMonth

  • myCalendarEvents被更新(不包括在我上面的代码中)
  • selectedDate已被更新(didSetselectedDate中将完成此操作)

有点长,但我认为值得一试。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52618609

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文