Main Objective: In first view controller I shall tap on a button in a cell -> button calls entity.removeFrom" "(_ value: " " ) method -> automatically should remove the corresponding cell from a table view in a second view controller.
What is Occurring: " " ... entity.removeFrom" "(_ value: " " ) method -> object is removed, set to nil, however NSFetchedResultsController is not deleting the respective rows. Leaving the tableview filled with empty cells ( from the remaining nil objects )
Question: How to remove many object in the to-many relationship and update the NSFetchedResultsController accordingly.
About the app Using swift 3 I am creating a basic To-Do list app with a tab bar controller.
First tab = A tableView of ToDoItem
Second tab = Finished toDoItems in an NSFetchedResultsController
Core Data Entities:
FinishedCollection, ToDoItem
FinishedCollection has a one-to-many relationship with todoItems (destination is ToDoItem)
Order of operation:
First Tab
1) Set ToDoItem attribute isFinished
2) FinishedCollection.addToToDoItems(toDoItem) or FinishedCollection.removeFromToDoItems(toDoItem)
3) Automatically Update Second Tab NSFetchedResultsController
PROBLEM:
When I removeFromToDoItems(toDoItem) the property in the NSFetchedResults controller is set to nil rather than removing the object entirely( I don't necessarily want to remove the object entirely) Resulting in empty cells and a million-frazillion nil objects. How do I approach removing the many nil objects in the one-to-many relationship and only having finished toDoItems in the NSFetchedResults controller tableview tab.
-
Attempt to filter nil objects when setting numberOfRowsInSection tableview method. Does not seem to do anything in this circumstance
let notNilObjects = sectionInfo.objects.flatMap { 0 }
TableViewDataSource methods
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let sections = fetchedResultsController?.sections
let sectionInfo = sections?[section]
return sectionInfo?.numberOfObjects ?? 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell( withIdentifier: "JournalCell", for: indexPath )
configure(cell, atIndexPath: indexPath)
return cell
}
//NSFetchedResultsDelegate methods
fileprivate func configure(_ cell: UITableViewCell, atIndexPath indexPath: IndexPath) {
guard let selectedObject = fetchedResultsController?.object(at: indexPath) else {
fatalError("Unexpected Object in FetchedResultsController")
}
let toDoItems = selectedObject.dayTasks?.allObjects as! [ToDoItem]
let toDo = ToDoItems.last
print(toDo?.name)
}
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(NSIndexSet(index: sectionIndex) as IndexSet, with: .fade)
case .delete:
tableView.deleteSections(NSIndexSet(index: sectionIndex) as IndexSet, with: .fade)
case .move:
break
case .update:
tableView.reloadData()
}
}
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:
configure(tableView.cellForRow(at: indexPath!)!, atIndexPath: indexPath!)
case .move:
tableView.moveRow(at: indexPath!, to: newIndexPath!)
}
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.endUpdates()
}
func initializeFetchedResultsController() {
let request: NSFetchRequest = ToDoItem.fetchRequest()
request.sortDescriptors = [ NSSortDescriptor( key: "timestamp", ascending: true ),
NSSortDescriptor( key: "isAccomplished", ascending: true) ]
fetchedResultsController = NSFetchedResultsController( fetchRequest : request,
managedObjectContext: CoreDataHelper.context,
sectionNameKeyPath : nil,
cacheName : nil )
fetchedResultsController?.delegate = self
do {
try fetchedResultsController?.performFetch()
}
catch {
print("Couldn't fetch results controller")
}
}
FinishedCollectioninstead of just relying on theisFinishedproperty? - Jon Rosepredicateto yourNSFetchRequestto filter out theToDoItemthat you don't want to display - Jon Rose