更改数据和 popViewController 后 TableView 不会重新加载

Posted

技术标签:

【中文标题】更改数据和 popViewController 后 TableView 不会重新加载【英文标题】:TableView doesn't reload after change data and popViewController 【发布时间】:2019-09-08 15:19:37 【问题描述】:

在我的应用程序中,我使用 NSFetchedResultsControllerDelegate 在添加新数据后重新加载 Tableview,但此解决方案仅在我第一次访问视图时有效。

如果我删除数据并再次添加,则信息不会出现在表格视图中。为此,我需要离开视图并再次访问它。

我尝试使用 Delegates 和 CallBack 重新加载表格视图,但没有成功。

我发现在删除旧数据后立即添加新数据后不会调用 cellForRowAt。虽然 numberOfSections 已被调用。

我迷路了。有人可以帮我吗?

Here is the video with app behaviour

在这里,我向您展示了我的代码的一些部分:

我的 NSFetchedResultsControllerDelegate

extension MeasureController: NSFetchedResultsControllerDelegate 

func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) 
    switch type 
    case .insert:
        myTableView.insertSections(IndexSet(integer: sectionIndex), with: .fade)
    case .delete:
        myTableView.deleteSections(IndexSet(integer: sectionIndex), with: .fade)
    case .move:
        break
    case .update:
        myTableView.reloadSections(IndexSet(integer: sectionIndex), with: .fade)
    @unknown default:
        fatalError()
    



func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) 
    myTableView.reloadData()
    myCollectionView.reloadData()


//Allow to show full section name in header.
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, sectionIndexTitleForSectionName sectionName: String) -> String? 
    return sectionName

MeasureController 中的 viewWillAppear 具有表格视图

override func viewWillAppear(_ animated: Bool) 
    super.viewWillAppear(animated)

    self.fillDataInTheView()
    self.allMeasures = CoreDataManager.shared.loadAllMeasuresByAthlete(athlete: athleteToShow)

    //Get the last recorded date that has measures records
    if let allMeasures = self.allMeasures, let selectedDay = CoreDataManager.shared.getLastDayWithMeasures(measure: allMeasures) 
        self.selectedDay = selectedDay
    

    if selectedDay != nil 
        if let measureByAthleteAndDay = CoreDataManager.shared.loadAllMeasuresByAthleteAndDay(athlete: athleteToShow, day: selectedDay) 
            self.measureByAthleteAndDay = measureByAthleteAndDay
        

        do 
            try fetchedRCAllMeasuresByDay.performFetch()
         catch let fetchedError 
            print("Error fetching Measures by Day:", fetchedError)
        
    

    do 
        try fetchedRCDay.performFetch()
     catch let err 
        print(err)
    

    if let lastEvaluation = getRecentDate() 
        lbEvaluationDate.text = "Última Avaliação: \(lastEvaluation.mediumDate())"
     else 
        lbEvaluationDate.text = "Sem Avaliação Registrada"
    

    self.myTableView.reloadData()

这是我的 myCollectioView 日期数据

extension MeasureController: UICollectionViewDelegate, UICollectionViewDataSource 

// MARK: - Collection View Data Source

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int 
    guard let dates = fetchedRCDay.fetchedObjects else return 0
    return dates.count


func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
    let cell = myCollectionView.dequeueReusableCell(withReuseIdentifier: cellCollectionViewID, for: indexPath) as! DateCollectionCell
    let day = fetchedRCDay.object(at: indexPath)
    if let date = day.title 
        cell.setupCell(date: date)
    

    if day == selectedDay 
        cell.isSelected = true
     else 
        cell.isSelected = false
    

    cell.delegate = self

    return cell


// MARK: - Collection View Delegate

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) 
    self.selectedCell(true, indexPath: indexPath)
    let day = fetchedRCDay.object(at: indexPath)
    self.alertToCreateEvaluation(day: day)
    myCollectionView.reloadData()


func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) 
    self.selectedCell(false, indexPath: indexPath)
    let day = fetchedRCDay.object(at: indexPath)
    if let date = day.title 
        lbEvaluationDate.text = "Data da Avaliação: \(date.mediumDate())"
    


func hasMeasures(cell: DateCollectionCell, day: Day) 

    if day.allMeasures == nil 
        cell.ivIndicator.isHidden = true
     else 
        cell.ivIndicator.isHidden = false
    

如果您需要更多代码来更好地理解它,请告诉我。

【问题讨论】:

如果可能,然后发布可共享演示项目的链接。 我发现只要删除旧数据,添加新数据后就不会调用cellForRowAt。尽管已调用 numberOfSections,但该值为零。但是如果你回到上一个视图重新进入MeasureView,numberOfSections 就会有一个正确的值,也就是说,numberOfSections 将是非零的。 那么,现在可以了吗? @Afonso 问题解决了吗? 您对beginUpdatesendUpdates 的电话在哪里?请参阅 Apple 文档以获取 NSFetcedResultsControllerDelegate 【参考方案1】:

试试这个...根据NSFetchedResultControllerDelegate 的 Apple 文档...

添加一个新的实例方法:

func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) 

    tableView.beginUpdates()

更改您现有的controllerDidChangeContent(_:) 实例方法:

func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) 

    tableView.endUpdates()

省略对.reloadData() 的调用 - 这些是“蛮力”便捷方法,可重新加载整个表或集合视图,并使微妙的 FRC 委托方法的使用变得多余。

【讨论】:

不幸的是,我之前尝试过这种方法,但没有成功。我又试了一次,但行为是一样的。我不知道我的问题是我在同一个视图控制器中有一个 tableView 和一个 conllectionView,只有一个扩展名为 NSFetchedResultsControllers。 每个VC的数据源都一样吗?或者换句话说,collection view 是否呈现与 table view 相同的数据?

以上是关于更改数据和 popViewController 后 TableView 不会重新加载的主要内容,如果未能解决你的问题,请参考以下文章

popViewController 和 pushViewController 动画

无法返回 - popViewController Animated 不工作,向后滑动也不工作

prepareForSegue 和 popViewController 的兼容性

PopViewController 正在占用内存

如何在没有警告和错误的闭包内使用 navigationController?.popViewController(animated: true)?

为啥 ARC 在 popViewController 之后不释放内存