使用 CoreData 和 NSFetchedResultsController 删除 UITableView 行
Posted
技术标签:
【中文标题】使用 CoreData 和 NSFetchedResultsController 删除 UITableView 行【英文标题】:Delete UITableView row w/ CoreData and NSFetchedResultsController 【发布时间】:2016-12-03 11:55:41 【问题描述】:在尝试从 tableView 中删除一行后,应用程序终止并出现以下错误:
Terminating app due to uncaught exception
'NSInternalInconsistencyException', reason: '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 (2), plus or minus
the number of rows inserted or deleted from that section (0 inserted,
1 deleted) and plus or minus the number of rows moved into or out of
that section (0 moved in, 0 moved out).'
代码如下:
import UIKit
import CoreData
class PlayerTableViewController: UITableViewController
lazy var fetchedResultsController:NSFetchedResultsController<TCSpieler> =
let fetch:NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "TCSpieler")
let sortByName = NSSortDescriptor(key: "name", ascending: true)
fetch.sortDescriptors = [sortByName]
let managedObjectContext = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let frc = NSFetchedResultsController(fetchRequest: fetch, managedObjectContext: managedObjectContext, sectionNameKeyPath: nil, cacheName: nil)
try! frc.performFetch()
return frc as! NSFetchedResultsController<TCSpieler>
()
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int
return fetchedResultsController.sections?.count ?? 1
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
return fetchedResultsController.sections![section].numberOfObjects
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
let cell = tableView.dequeueReusableCell(withIdentifier: "PlayerCell", for: indexPath) as! PlayerTableViewCell
// Configure the cell...
cell.player = fetchedResultsController.object(at: indexPath)
return cell
// Override to support conditional editing of the table view.
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool
// Return false if you do not want the specified item to be editable.
return true
// Override to support editing the table view.
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath)
if editingStyle == .delete
let rowToDelete = fetchedResultsController.object(at: indexPath)
fetchedResultsController.managedObjectContext.delete(rowToDelete)
try! fetchedResultsController.managedObjectContext.save()
// Delete the row from the data source
tableView.deleteRows(at: [indexPath], with: .fade)
else if editingStyle == .insert
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
【问题讨论】:
尝试使用断点并检查您是否正确删除了fetchedResultsController
中的数据
你实现NSFetchedResultsController
的委托方法了吗?
第 2 部分在删除之前有多少行?
【参考方案1】:
这适用于 swift 4
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath)
if editingStyle == UITableViewCellEditingStyle.delete
let managedObjectContext: NSManagedObjectContext = (UIApplication.shared.delegate as! AppDelegate).managedObjectContext;
let managedObject: NSManagedObject = fetchedResultsController.object(at: indexPath) as! NSManagedObject;
managedObjectContext.delete(managedObject);
do
try managedObjectContext.save();
catch
// Error occured while deleting objects
else if editingStyle == UITableViewCellEditingStyle.insert
以下内容还将负责更新 UI 当数据库更新时
extension PlayerTableViewController: NSFetchedResultsControllerDelegate
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>)
self. tableView.beginUpdates()
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! as IndexPath], with: .fade)
case .delete:
self. tableView.deleteRows(at: [indexPath! as IndexPath], with: .fade)
case .update:
if(indexPath != nil)
let cell = self. tableView.cellForRow(at: indexPath! as IndexPath)
case .move:
self. tableView.deleteRows(at: [indexPath! as IndexPath], with: .fade)
self. tableView.insertRows(at: [indexPath! as IndexPath], with: .fade)
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>)
self. tableView.endUpdates()
【讨论】:
【参考方案2】:这对我有用:
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath)
if editingStyle == UITableViewCellEditingStyle.delete
let managedObjectContext: NSManagedObjectContext = (UIApplication.shared.delegate as! AppDelegate).managedObjectContext;
let managedObject: NSManagedObject = fetchedResultsController.object(at: indexPath) as! NSManagedObject;
managedObjectContext.delete(managedObject);
do
try managedObjectContext.save();
tableView.deleteRows(at: [indexPath], with: UITableViewRowAnimation.fade);
catch
// Error occured while deleting objects
else if editingStyle == UITableViewCellEditingStyle.insert
【讨论】:
以上是关于使用 CoreData 和 NSFetchedResultsController 删除 UITableView 行的主要内容,如果未能解决你的问题,请参考以下文章
使用 xmpp 获取 XMPPGroupCoreDataStorageObject,但 NSManagingContextDidSaveChangesNotification 似乎不起作用
Coredata 和 Mogenerator,coredata 标志并发问题 EXC_BAD_INSTRUCTION
将 UICollectionView 与 CoreData 和 NSFetchedResultsController 一起使用