Hi,
I have the following problem with this code: for a project I display a list of tasks in a tableview. The list is divided in 3 sections: open, in progress, complete (based on the task status). When I now create the tasks with the proper status and go back to the list, the items appear in the correct section. I can add more tasks and the list gets updated properly.
But when I now close the program and start it again, the tasks are displayed in the wrong sections. For example
This is how the table view looks like while I am creating the tasks
- Open
- open_1
- open_2
- In Progress
- progress_1
- progress_2
- Complete
- comp_1
- comp_2
Now I close the program, start it again and look at the list, this is how it shows:
- Open
- progress_1
- progress_2
- In Progress
- open_1
- open_2
- Complete
- comp_1
- comp_2
Here is my code for the controller:
import UIKit
import CoreData
class TaskTableViewController: UITableViewController, NSFetchedResultsControllerDelegate {
var project: ProjectMO!
var tasks:[TaskMO] = []
var fetchResultController: NSFetchedResultsController<TaskMO>!
override func viewDidLoad() {
super.viewDidLoad()
let fetchRequest: NSFetchRequest<TaskMO> = TaskMO.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "project = %@", self.project)
let sortDescriptor = NSSortDescriptor(key: "name", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
if let appDelegate = (UIApplication.shared.delegate as? AppDelegate) {
let context = appDelegate.persistentContainer.viewContext
fetchResultController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: #keyPath(TaskMO.taskStatus), cacheName: nil)
fetchResultController.delegate = self
do {
try fetchResultController.performFetch()
if let fetchedObjects = fetchResultController.fetchedObjects {
tasks = fetchedObjects
}
} catch {
print(error)
}
}
/
/
/
/
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
/
}
/
override func numberOfSections(in tableView: UITableView) -> Int {
/
guard let sections = fetchResultController.sections else { return 0 }
print("Sections.count: " + String(sections.count))
return sections.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
guard let sectionInfo = fetchResultController.sections?[section] else { fatalError("Unexpected Section") }
print("Setting section titles: " + sectionInfo.name + "/" + String(sectionInfo.numberOfObjects))
return sectionInfo.numberOfObjects
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
guard let sectionInfo = fetchResultController.sections?[section] else { fatalError("Unexpected Section") }
return sectionInfo.name
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) {
print("didChange sectionInfo()")
switch type {
case .insert:
tableView.insertSections(IndexSet(integer: sectionIndex), with: .fade)
case .delete:
tableView.deleteSections(IndexSet(integer: sectionIndex), with: .fade)
default:
break;
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let task = fetchResultController.object(at: indexPath)
print(indexPath)
cell.textLabel?.text = task.name
return cell
}
/
/
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
/
return true
}
*/
/
/
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
/
tableView.deleteRows(at: [indexPath], with: .fade)
} else if editingStyle == .insert {
/
}
}
*/
/
/
override func tableView(_ tableView: UITableView, moveRowAt fromIndexPath: IndexPath, to: IndexPath) {
}
*/
/
/
override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
/
return true
}
*/
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.beginUpdates()
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
print("didChange anObject()")
switch type {
case .insert:
if let newIndexPath = newIndexPath{
tableView.insertRows(at: [newIndexPath], with: .fade)
}
case .delete:
if let indexPath = indexPath {
tableView.deleteRows(at: [indexPath], with: .fade)
}
default:
tableView.reloadData()
}
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.endUpdates()
}
override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
/
let deleteAction = UITableViewRowAction(style: UITableViewRowActionStyle.default, title: "Delete",handler: { (action, indexPath) -> Void in
if let appDelegate = (UIApplication.shared.delegate as? AppDelegate) {
let context = appDelegate.persistentContainer.viewContext
let objectToDelete = self.fetchResultController.object(at: indexPath)
context.delete(objectToDelete)
appDelegate.saveContext()
}
})
return[deleteAction]
}
/
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "addTaskToProject" {
let destinationController = segue.destination as! AddTaskToProjectTableViewController
destinationController.project = project
destinationController.editMode = false
} else if segue.identifier == "editTaskToProject" {
if let indexPath = tableView.indexPathForSelectedRow {
let destinationController = segue.destination as! AddTaskToProjectTableViewController
destinationController.project = project
destinationController.task = fetchResultController.object(at: indexPath)
destinationController.editMode = true
destinationController.title = "Show task"
}
}
}
@IBAction func close(segue:UIStoryboardSegue) {
print("icoming close from task creation close()")
/
if project.tasks != nil {
tasks = project.tasks?.allObjects as! [TaskMO]
tasks = tasks.sorted(by: { $0.name! < $1.name! })
print("close() tasks.count: " + String(tasks.count))
}
*/
tableView.reloadData()
}
@IBAction func unwindFromTask(segue:UIStoryboardSegue){
print("icoming close from task creation unwindFromTask()")
/
if project.tasks != nil {
tasks = project.tasks?.allObjects as! [TaskMO]
tasks = tasks.sorted(by: { $0.name! < $1.name! })
print("unwindFromTask() tasks.count: " + String(tasks.count))
for task in tasks {
print(task.name!)
}
}
*/
tableView.reloadData()
}
}
Any ideas why it is doing that?
Max