Reputation: 748
I'm learning CoreData on mac os. I have a demo program which basically works, except that when I delete a row from my tableView,
fetchedResultsController.fetchedObjects?.count
hasn't updated.
Revelevant properties are defined as follows
var container: NSPersistentContainer!
var fetchedResultsController: NSFetchedResultsController<Commit>!
var count: Int { get {
if fetchedResultsController == nil { return 0 }
return fetchedResultsController.fetchedObjects?.count ?? 0
} }
The remove method:
func remove(itemAt index: Int) {
guard let n = fetchedResultsController.fetchedObjects?.count,
index < n && index >= 0,
let commit = fetchedResultsController.fetchedObjects?[index] else { return }
container.viewContext.delete(commit)
saveContext()
ddt("remove \(count)", caller: self)
}
The count after remove hasn't been updated, however the persistent store is correct. If I remove another row, it still doesn't update, but if I change predicate (even to the nil predicate) it refreshes properly.
On relaunch, all is updated.
My delegate doesn't do anything. The table gets updated in its delegate:
func tableView(_ tableView: NSTableView, rowActionsForRow row: Int, edge: NSTableView.RowActionEdge) -> [NSTableViewRowAction] {
// left swipe
if edge == .trailing {
let deleteAction = NSTableViewRowAction(style: .destructive, title: "Delete", handler: {
[unowned self] (rowAction, row) in
self.dataContainer.remove(itemAt: row)
tableView.removeRows(at: [row], withAnimation: .slideLeft)
})
deleteAction.backgroundColor = NSColor.red
return [deleteAction]
}
// Anything other than left does nothing
return []
}
What have I left out?
(ddt, for those too young to remember, was an insecticide banned many years ago because it tended to propagate up the food chain, killing off birds, among other species. I think it's safe to use on bugs in Swift.)
Upvotes: 1
Views: 827
Reputation: 285059
First of all declare the fetchedResultsController
as lazy non-optional property and set the delegate in the closure
lazy var fetchedResultsController: NSFetchedResultsController<Commit> = {
...
let controller = NSFetchedResultsController( ...
controller.delegate = self
...
return controller
}()
Adopt NSFetchedResultsControllerDelegate
and implement the delegate methods
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>)
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?)
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>)
To delete a record in a NSTableViewRowAction
get the item at indexPath and delete the record in the Core Data stack. You don't need to check the index, the row does exist
let indexPath = IndexPath(item: row, section: 0)
let commit = fetchedResultsController.object(at: indexPath)
container.viewContext.delete(commit)
saveContext()
The NSFetchedResultsControllerDelegate
methods manage the update of the UI
Upvotes: 3