Swift / TableView可重用Cell每次显示时都会加载不同的内容

时间:2016-09-23 18:41:57

标签: ios swift tableview

我有UITableViewController。在第1部分中,有一个显示JTAppleCalendar的单元格,容易填充:

    if indexPath.section == 1 {

        let cell = tableView.dequeueReusableCellWithIdentifier("calendarViewCell") as! CalendarViewCell

        print(eventDatesAsNSDates)
        cell.calendarView.selectDates(eventDatesAsNSDates)            
        return cell
    }

eventDatesAsNSDates填充在viewDidAppear

理论上,一切都按我的意愿运作。但是如果我向下和向上滚动TableView,就会发生完全令人讨厌的行为。

enter image description here

cellForRowAtIndexPath print(eventDatesAsNSDates)中的print语句证明eventDatesAsNSDates没有改变,但日历仍然被填充一次而不是另一次,然后再次填充......

App中的其他时间都不会设置或调用cell.calendarView.selectDateseventDatesAsNSDates

我错过了什么?非常感谢帮助。

根据要求,selectDates函数:

public func selectDates(dates: [NSDate], triggerSelectionDelegate: Bool = true, keepSelectionIfMultiSelectionAllowed: Bool = false) {
        var allIndexPathsToReload: [NSIndexPath] = []
        var validDatesToSelect = dates
        // If user is trying to select multiple dates with multiselection disabled, then only select the last object
        if !calendarView.allowsMultipleSelection && dates.count > 0 { validDatesToSelect = [dates.last!] }

        let addToIndexSetToReload = {(indexPath: NSIndexPath)->Void in
            if !allIndexPathsToReload.contains(indexPath) { allIndexPathsToReload.append(indexPath) } // To avoid adding the  same indexPath twice.
        }

        let selectTheDate = {(indexPath: NSIndexPath, date: NSDate) -> Void in
            self.calendarView.selectItemAtIndexPath(indexPath, animated: false, scrollPosition: .None)
            addToIndexSetToReload(indexPath)
            // If triggereing is enabled, then let their delegate handle the reloading of view, else we will reload the data
            if triggerSelectionDelegate {
                self.internalCollectionView(self.calendarView, didSelectItemAtIndexPath: indexPath)
            } else { // Although we do not want the delegate triggered, we still want counterpart cells to be selected

                // Because there is no triggering of the delegate, the cell will not be added to selection and it will not be reloaded. We need to do this here
                self.addCellToSelectedSetIfUnselected(indexPath, date: date)
                let cellState = self.cellStateFromIndexPath(indexPath, withDate: date)
                if let aSelectedCounterPartIndexPath = self.selectCounterPartCellIndexPathIfExists(indexPath, date: date, dateOwner: cellState.dateBelongsTo) {
                    // If there was a counterpart cell then it will also need to be reloaded
                    addToIndexSetToReload(aSelectedCounterPartIndexPath)
                }
            }
        }

        let deSelectTheDate = { (oldIndexPath: NSIndexPath) -> Void in
            addToIndexSetToReload(oldIndexPath)
            if let index = self.theSelectedIndexPaths.indexOf(oldIndexPath) {
                let oldDate = self.theSelectedDates[index]
                self.calendarView.deselectItemAtIndexPath(oldIndexPath, animated: false)
                self.theSelectedIndexPaths.removeAtIndex(index)
                self.theSelectedDates.removeAtIndex(index)

                // If delegate triggering is enabled, let the delegate function handle the cell
                if triggerSelectionDelegate {
                    self.internalCollectionView(self.calendarView, didDeselectItemAtIndexPath: oldIndexPath)
                } else { // Although we do not want the delegate triggered, we still want counterpart cells to be deselected
                    let cellState = self.cellStateFromIndexPath(oldIndexPath, withDate: oldDate)
                    if let anUnselectedCounterPartIndexPath = self.deselectCounterPartCellIndexPath(oldIndexPath, date: oldDate, dateOwner: cellState.dateBelongsTo) {
                        // If there was a counterpart cell then it will also need to be reloaded
                        addToIndexSetToReload(anUnselectedCounterPartIndexPath)
                    }
                }
            }
        }

        for date in validDatesToSelect {
            let components = self.calendar.components([.Year, .Month, .Day],  fromDate: date)
            let firstDayOfDate = self.calendar.dateFromComponents(components)!

            // If the date is not within valid boundaries, then exit
            if !(firstDayOfDate >= self.startOfMonthCache && firstDayOfDate <= self.endOfMonthCache) { continue }
            let pathFromDates = self.pathsFromDates([date])

            // If the date path youre searching for, doesnt exist, then return
            if pathFromDates.count < 0 { continue }
            let sectionIndexPath = pathFromDates[0]

            // Remove old selections
            if self.calendarView.allowsMultipleSelection == false { // If single selection is ON
                let selectedIndexPaths = self.theSelectedIndexPaths // made a copy because the array is about to be mutated
                for indexPath in selectedIndexPaths {
                    if indexPath != sectionIndexPath { deSelectTheDate(indexPath) }
                }

                // Add new selections
                // Must be added here. If added in delegate didSelectItemAtIndexPath
                selectTheDate(sectionIndexPath, date)
            } else { // If multiple selection is on. Multiple selection behaves differently to singleselection. It behaves like a toggle. unless keepSelectionIfMultiSelectionAllowed is true.
                // If user wants to force selection if multiselection is enabled, then removed the selected dates from generated dates
                if keepSelectionIfMultiSelectionAllowed {
                    if selectedDates.contains(calendar.startOfDayForDate(date)) {
                        addToIndexSetToReload(sectionIndexPath)
                        continue // Do not deselect or select the cell. Just add it to be reloaded
                    }
                }
                if self.theSelectedIndexPaths.contains(sectionIndexPath) { // If this cell is already selected, then deselect it
                    deSelectTheDate(sectionIndexPath)
                } else {
                    // Add new selections
                    // Must be added here. If added in delegate didSelectItemAtIndexPath
                    selectTheDate(sectionIndexPath, date)
                }
            }
        }


        // If triggering was false, although the selectDelegates weren't called, we do want the cell refreshed. Reload to call itemAtIndexPath
        if /*triggerSelectionDelegate == false &&*/ allIndexPathsToReload.count > 0 {
            delayRunOnMainThread(0.0) {
                self.batchReloadIndexPaths(allIndexPathsToReload)
            }
        }
    }

1 个答案:

答案 0 :(得分:1)

每次您的单元格再次可见时,cellForRow委托方法都会尝试更新tableView行/部分。

我肯定会在其他地方准备数据(用于日历),我更愿意仅渲染数据。 UITableViewCell的可重用性将正确处理内容。

不要在cellForRow方法中调用该方法。尝试放置它,例如进入viewDidAppear()方法。如果selectDates()方法完成了更新tableView的所有工作,它仍然可以正常工作。