You should always use "NSFetchedResultsController" whenever tableview deals with the Core Data, because "NSFetchedResultsController" is built keeping tableView in mind.
It provides features which are useful for dealing with tableView
- Along with UITableViewDelegate & UITableviewdatasource protocols, adopt/conform to "NSFetchedResultsControllerDelegate" protocol.
- Then implement its 3 methods to delete the record from core data. And DON'T RELOAD the tableview. NSFetchedResultsController will take care of it.
for eg. let's load the data from core data (Entity name = Movie)
var fetchedResultsController: NSFetchedResultsController<Movie>
override func viewDidLoad()
{
super.viewDidLoad()
loadData()
}
func loadData()
{
fetchedResultController = getMovies(managedObjectContext: self.coreData.persistentContainer.viewContext)
fetchedResultController.delegate = self
}
func getMovies(managedObjectContext: NSManagedObjectContext) -> NSFetchedResultsController<Movie>
{
let fetchedResultController: NSFetchedResultsController<Movie>
let request: NSFetchRequest<Movie> = Movie.fetchRequest()
let formatSort = NSSortDescriptor(key: "format", ascending: false)
let nameSort = NSSortDescriptor(key: "title", ascending: true)
request.sortDescriptors = [formatSort, nameSort]
fetchedResultController = NSFetchedResultsController(fetchRequest: request, managedObjectContext: managedObjectContext, sectionNameKeyPath: "format", cacheName: "MyMovieLibrary")
do
{
try fetchedResultController.performFetch()
}
catch
{
fatalError("Error in fetching records")
}
return fetchedResultController
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int
{
if let sections = fetchedResultController.sections
{
return sections.count
}
return 0
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
if let sections = fetchedResultController.sections
{
let currentSection = sections[section]
return currentSection.numberOfObjects
}
return 0
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "movieCell", for: indexPath) as! MovieTableViewCell
let movie = fetchedResultController.object(at: indexPath)
cell.configureCell(movie: movie)
return cell
}
Delete a record from core data
// Override to support editing the table view.
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath)
{
let managedObjectContext = coreData.persistentContainer.viewContext
if editingStyle == .delete
{
movieToDelete = fetchedResultController.object(at: indexPath)
let confirmDeleteAlertController = UIAlertController(title: "Remove Movie", message: "Are you sure you would like to delete "(movieToDelete!.title!)" from your movie library?", preferredStyle: UIAlertControllerStyle.actionSheet)
let deleteAction = UIAlertAction(title: "Delete", style: UIAlertActionStyle.default, handler: { [weak self] (action: UIAlertAction) -> Void in
managedObjectContext.delete((self?.movieToDelete!)!)
self?.coreData.saveContext()
self?.movieToDelete = nil
})
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel, handler: { [weak self] (action: UIAlertAction) -> Void in
self?.movieToDelete = nil
})
confirmDeleteAlertController.addAction(deleteAction)
confirmDeleteAlertController.addAction(cancelAction)
present(confirmDeleteAlertController, animated: true, completion: nil)
}
}
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>)
{
tableView.beginUpdates()
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?)
{
switch type
{
case NSFetchedResultsChangeType.delete:
print("NSFetchedResultsChangeType.Delete detected")
if let deleteIndexPath = indexPath
{
tableView.deleteRows(at: [deleteIndexPath], with: UITableViewRowAnimation.fade)
}
case NSFetchedResultsChangeType.insert:
print("NSFetchedResultsChangeType.Insert detected")
case NSFetchedResultsChangeType.move:
print("NSFetchedResultsChangeType.Move detected")
case NSFetchedResultsChangeType.update:
print("NSFetchedResultsChangeType.Update detected")
tableView.reloadRows(at: [indexPath!], with: UITableViewRowAnimation.fade)
}
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>)
{
tableView.endUpdates()
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…