gpt4 book ai didi

swift - 部分索引更改时 NSFetchedResultsController 崩溃

转载 作者:行者123 更新时间:2023-11-28 06:29:42 24 4
gpt4 key购买 nike

我正在 Xcode 8 中使用 Swift 3(已转换)编写我的应用程序。

NSFetchedResultsController 导致我出现严重的应用程序错误。

我的主 TableView 由一个名为“yearText”的文本标识符分隔,当用户使用日期选择器更改“事件日期”时,该标识符将设置在任何给定的事件记录 (NSManagedObject) 上。当采摘器更改或解雇时,该年份从日期开始剥离,转换为文本并存储在事件对象中。然后保存托管对象上下文。

如果选择的日期已经存在一个部分(即“2020 年”),则会抛出一个错误:

[error] error: Serious application error. An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:. Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (2) must be equal to the number of rows contained in that section before the update (1), plus or minus the number of rows inserted or deleted from that section (0 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out). with userInfo (null)

只要选择的日期不在已经有以它命名的部分的年份之内,一切都可以正常进行。

这是我更新数据库和tableview的相关代码:

var fetchedResultsController: NSFetchedResultsController<NSFetchRequestResult> {
if _fetchedResultsController != nil {
return _fetchedResultsController!
}

// Fetch the default object (Event)
let fetchRequest = NSFetchRequest<NSFetchRequestResult>()
let entity = NSEntityDescription.entity(forEntityName: "Event", in: managedObjectContext!)
fetchRequest.entity = entity

// Set the batch size to a suitable number.
fetchRequest.fetchBatchSize = 60

// Edit the sort key as appropriate.
let sortDescriptor = NSSortDescriptor(key: "date", ascending: false)

fetchRequest.sortDescriptors = [sortDescriptor]

// Edit the section name key path and cache name if appropriate.
// nil for section name key path means "no sections".
let aFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managedObjectContext!, sectionNameKeyPath: "yearText", cacheName: nil)
aFetchedResultsController.delegate = self
_fetchedResultsController = aFetchedResultsController

do {
try _fetchedResultsController!.performFetch()
} catch {
// Implement error handling code here.
abort()
}

return _fetchedResultsController!
}
var _fetchedResultsController: NSFetchedResultsController<NSFetchRequestResult>?


// MARK: - UITableViewDelegate

extension EventListViewController: UITableViewDelegate {

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as! EventCell
cell.isSelected = true
configureCell(withCell: cell, atIndexPath: indexPath)
}

func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as! EventCell
cell.isSelected = false
configureCell(withCell: cell, atIndexPath: indexPath)
}
}


// MARK: - UITableViewDataSource

extension EventListViewController: UITableViewDataSource {

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

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

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "EventCell", for: indexPath) as! EventCell
configureCell(withCell: cell, atIndexPath: indexPath)
return cell
}

func configureCell(withCell cell: EventCell, atIndexPath indexPath: IndexPath) {
// bunch of stuff to make the cell pretty and display the data
}

func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the specified item to be editable.
return true
}

func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
let context = fetchedResultsController.managedObjectContext
context.delete(fetchedResultsController.object(at: indexPath) as! NSManagedObject)
do {
try context.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
//print("Unresolved error \(error), \(error.userInfo)")
abort()
}
}
}

func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let sectionInfo = fetchedResultsController.sections![section]
return sectionInfo.name
}

func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
// make the section header look good
view.tintColor = kWPPTintColor
let header = view as! UITableViewHeaderFooterView
header.textLabel?.textColor = kWPPDarkColor
header.textLabel?.font = UIFont.preferredFont(forTextStyle: UIFontTextStyle.subheadline)
}
}


// MARK: - NSFetchedResultsControllerDelegate

extension EventListViewController: NSFetchedResultsControllerDelegate {

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

func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) {
switch type {
case .insert:
tableView.insertSections(IndexSet(integer: sectionIndex), with: .fade)
case .delete:
tableView.deleteSections(IndexSet(integer: sectionIndex), with: .fade)
default:
return
}
}

func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
switch type {
case .insert:
tableView.insertRows(at: [newIndexPath!], with: .fade)
case .delete:
tableView.deleteRows(at: [indexPath!], with: .fade)
case .update:
configureCell(withCell: tableView.cellForRow(at: indexPath!)! as! EventCell, atIndexPath: indexPath!)
case .move:
tableView.moveRow(at: indexPath!, to: newIndexPath!)
}
}

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

我希望你能给我一些建议。谢谢。

编辑:删除了一些阻碍并修改 .move 以使用 .moveRow 的代码

编辑 2:添加了 FRC 生成代码。

最佳答案

我在更新 Core Data 托管对象的某些属性时遇到了同样的错误。

这是我的 Controller 功能:

func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
switch type {
case .insert:
self.tableView.insertRows(at: [newIndexPath!], with: .fade)
case .delete:
self.tableView.deleteRows(at: [indexPath!], with: .fade)
case .update:
self.tableView.reloadRows(at: [indexPath!], with: .fade)
case .move:
self.tableView.insertRows(at: [newIndexPath!], with: .fade)
self.tableView.deleteRows(at: [indexPath!], with: .fade)
}
}

在更新案例中使用 newIndexPath 之前,我发现当获取结果 Controller 执行某些更新操作时,这会导致某些部分行不匹配问题。相反,将 indexPath 用于更新案例就可以了。

关于swift - 部分索引更改时 NSFetchedResultsController 崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40700770/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com