【问题标题】:NSFetchedResultsController doesn't respond to changes in the number of sectionsNSFetchedResultsController 不响应节数的变化
【发布时间】:2020-11-28 06:49:58
【问题描述】:

当我从表格视图中删除单元格时出现以下错误:

无效更新:节数无效。段数 更新后的表视图中包含的 (0) 必须等于 更新前表格视图中包含的部分数(1), 加上或减去插入或删除的节数(0 插入, 0 条已删除)

我正在使用NSFetchedResultsControllerDelegate 来响应节数的变化。我正在从 Core Data 中的 plist 文件中检索数据,并且每次添加表格视图单元格都会相应地增加部分的数量,因此 3 个单元格 = 3 个部分。

override func numberOfSections(in tableView: UITableView) -> Int {
    return fetchedResultsController.sections?.count ?? 0
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    let sectionInfo = fetchedResultsController.sections![section]
    return sectionInfo.numberOfObjects
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
    let goal = fetchedResultsController.object(at: indexPath)
    cell.textLabel!.text = goal.title
    return cell
}

override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
    if editingStyle == .delete {
        let goal = fetchedResultsController.object(at: indexPath)
        self.context.delete(goal)
        self.saveContext()
    }
}

func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
    switch type {
    case .delete:
        tableView.deleteRows(at: [indexPath!], with: .automatic)
    default:
        break
    }
}

func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) {
    let section = IndexSet(integer: sectionIndex)
    switch type {
    case .delete:
        tableView.deleteSections(section, with: .automatic)
    default:
        break
    }
}

context是这个:

var context : NSManagedObjectContext {
    let appDelegate = UIApplication.shared.delegate as! AppDelegate
    return appDelegate.persistentContainer.viewContext
}

我如何将保存的核心数据加载到 FRC:

func loadSavedData() {
    if fetchedResultsController == nil {
        let request = Goal.createFetchRequest()
        let sort = NSSortDescriptor(key: "date", ascending: false)
        request.sortDescriptors = [sort]
        request.fetchBatchSize = 20
        
        fetchedResultsController = NSFetchedResultsController(fetchRequest: request, managedObjectContext: self.context, sectionNameKeyPath: "title", cacheName: nil)
        fetchedResultsController.delegate = self
    }
    
    fetchedResultsController.fetchRequest.predicate = goalPredicate
    
    do {
        try fetchedResultsController.performFetch()
        tableView.reloadData()
    } catch {
        print("Fetch failed")
    }
}

【问题讨论】:

  • 你的代码看起来很合理;我假设您已经删除了通常的插入/更新案例。您可以扩展“3 个单元格 = 3 个部分”吗?每个部分是否只有一个单元格?另外,您能展示一下您的 FRC 是如何设置的吗?
  • 当我在numberOfSections 函数中打印(fetchedResultsController.sections?.count) 时,数字随着单元格数量的增加而增加。 FRC不应该发生这种情况吗?我在我的问题中添加了如何将核心数据加载到 FRC。
  • 另外我在commit 函数中没有editingStyleinsert,因为我没有滑动或单击单元格来执行插入编辑,而只是删除。插入在另一个屏幕中完成,以保存到 Core Data 并加载到 viewDidLoad 中的当前页面。
  • 其实你是对的。我将NSFetchedResultsController(fetchRequest: request, managedObjectContext: self.context, sectionNameKeyPath: nil, cacheName: nil) 中的sectionNameKeyPath 更改为nil,现在它可以工作了。谢谢。

标签: ios swift uitableview core-data nsfetchedresultscontroller


【解决方案1】:

尝试在这些委托 API 中调用 beginUpdates 和 endUpdates。

func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
   tableView.endUpdates
}
    
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
   tableView.beginUpdates
}

如果您仍然遇到问题,那么在这个委托函数中,尝试这样调用:

func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
    tableView.performBatchUpdates {
        tableView.deleteRows(at: [indexPath], with: .automatic)
        tableView.deleteSections(section, with: .automatic)
    } completion: { (status) in
        
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-25
    • 2015-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多