Osama Naeem
Osama Naeem

Reputation: 1954

How to use NSFetchedResultsController to update tableview content

I am updating certain parts of coredata and I want the NSFetchedResultsController to automatically reload the tableview with all the animations. I am changing a coredata element that is used to sort tableview. I am doing this by swiping to the right on the cell and then changing that particular tableviewcell's priorityNumber to zero so that the task goes to the bottom and few other things. I want the table to reload but with the animations. right now I am just doing tableView.reload() and it's just not working right.

I want to see the animation of the cell going to the bottom of the device. Any help will be appreciated!

Here is the code: Changes I am bringing to the coreData:

func tableView(_ tableView: UITableView,
               leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?
{
    let closeAction = UIContextualAction(style: .normal, title:  "✓", handler: { (ac:UIContextualAction, view:UIView, success:(Bool) -> Void) in

        //???

        self.fetchedResultsController.object(at: indexPath).sTaskCompleted = !(self.fetchedResultsController.object(at: indexPath).sTaskCompleted)

        if ( self.fetchedResultsController.object(at: indexPath).sTaskCompleted)
        {
            print("Completed")
            //Change priority number to 0 after saving their current priority number in previousPN
            //Change priority circle color
            //Change background of the cell to something else




            self.fetchedResultsController.object(at: indexPath).sPreviousPN = self.fetchedResultsController.object(at: indexPath).sPriorityNumber
            self.fetchedResultsController.object(at: indexPath).sPriorityNumber = 0
            self.fetchedResultsController.object(at: indexPath).cellbackgroundColor = UIColor(red:0.93, green:0.91, blue:0.91, alpha:1.0)
            self.fetchedResultsController.object(at: indexPath).previousPriorityColor = self.fetchedResultsController.object(at: indexPath).sPriorityColor
            self.fetchedResultsController.object(at: indexPath).sPriorityColor = .clear

            var error: NSError?


            do {
                // Save The object

                try self.moContext.save()
                print("SAVED")
            } catch let error1 as NSError {
                error = error1
            }


            DispatchQueue.main.asyncAfter(deadline: .now() + 0.3, execute: {
                UIView.transition(with: tableView,
                                  duration: 0.15,
                                  options: .transitionCrossDissolve,
                                  animations: { self.tableView.reloadData() })
            })

        } else {
            print("InCompleted")


            self.fetchedResultsController.object(at: indexPath).sPriorityNumber =  self.fetchedResultsController.object(at: indexPath).sPreviousPN

            self.fetchedResultsController.object(at: indexPath).cellbackgroundColor = .white
            self.fetchedResultsController.object(at: indexPath).sPriorityColor = self.fetchedResultsController.object(at: indexPath).previousPriorityColor

            var error: NSError?


            do {
                // Save The object

                try self.moContext.save()
                print("SAVED")
            } catch let error1 as NSError {
                error = error1
            }
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.3, execute: {
                UIView.transition(with: tableView,
                                  duration: 0.15,
                                  options: .transitionCrossDissolve,
                                  animations: { self.tableView.reloadData() })
            })

        }

        success(true)

    })

    closeAction.backgroundColor = UIColor(red:0.18, green:0.87, blue:0.65, alpha:1.0)

    return UISwipeActionsConfiguration(actions: [closeAction])

}

Now how to use FRC delegate method (.update) to refresh the tableView with appropriate animations.

Upvotes: 2

Views: 1503

Answers (2)

rymerej
rymerej

Reputation: 561

The table view controller needs to conform to NSFetchedResultsControllerDelegate and implement its delegate methods. If configured correctly, the fetched results controller will watch the managed object context for changes and call the appropriate delegate method to update the table view with animations.

class TaskTableViewController: UITableViewController, NSFetchedResultsControllerDelegate {

    var fetchedResultsController: NSFetchedResultsController<Task>!

    override func viewDidLoad() {
        super.viewDidLoad()
        configureFetchedResultsController()
    }

    func configureFetchedResultsController() {

        if fetchedResultsController == nil {

            // 1. Get fetch request
            let fetchRequest: NSFetchRequest<Task> = Task.fetchRequest()

            // 2. Add sort descriptors
            fetchRequest.sortDescriptors = [NSSortDescriptor(key: "sPriorityNumber", ascending: false)]

            // 3. Configure the FRC
            fetchedResultsController = NSFetchedResultsController<Task>(fetchRequest: fetchRequest, managedObjectContext: CoreDataStack.context, sectionNameKeyPath: nil, cacheName: nil)

            // 4. Set the FRC delegate as self
            fetchedResultsController.delegate = self
        }

        // 5. Tell the FRC to start watching the MOC for changes
        do {
            try fetchedResultsController.performFetch()
        } catch {
            NSLog("Error starting fetched results controller  \(error)")
        }
    }

    // FRC delegate methods

    func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>,
                    didChange anObject: Any,
                    at indexPath: IndexPath?,
                    for type: NSFetchedResultsChangeType,
                    newIndexPath: IndexPath?) {
        switch type {
        case .insert:
            guard let newIndexPath = newIndexPath else { return }
            tableView.insertRows(at: [newIndexPath], with: .automatic)
        case .delete:
            guard let indexPath = indexPath else { return }
            tableView.deleteRows(at: [indexPath], with: .fade)
        case .move:
            tableView.reloadData()
        case .update:
            guard let indexPath = indexPath else { return }
            tableView.reloadRows(at: [indexPath], with: .automatic)
        }
    }

    func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>,
                    didChange sectionInfo: NSFetchedResultsSectionInfo,
                    atSectionIndex sectionIndex: Int,
                    for type: NSFetchedResultsChangeType) {
        switch type {
        case .delete:
            tableView.deleteSections(IndexSet(integer: sectionIndex), with: .automatic)
        case .insert:
            tableView.insertSections(IndexSet(integer: sectionIndex), with: .automatic)
        default:
            break
        }
    }
}

Upvotes: 1

ahmed
ahmed

Reputation: 51

You need to check tableview function **editing style **

Upvotes: 0

Related Questions