Search code examples
iosiphoneswiftcore-datansfetchedresultscontroller

Refresh NSFetchedResultController in Swift


I want to refresh NSFetchedResultController with different predicate if user clicks on an Action Sheet.

Here is the code:

lazy var fetchResultController: NSFetchedResultsController = {

    let fetchRequest = NSFetchRequest(entityName: "Debt")
    let filterText:String?
    let ascending:Bool?

    if NSUserDefaults.standardUserDefaults().objectForKey("filterType")?.stringValue == "name" {
        filterText = "name"
        ascending = true
    }
    else
    {
        filterText = "date"
        ascending = true
    }

    let sortDescriptor = NSSortDescriptor(key: filterText, ascending: ascending!)
    fetchRequest.sortDescriptors = [sortDescriptor]

    let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: CoreDataManager.sharedManager.managedObjectContext, sectionNameKeyPath: filterText, cacheName: nil)
    fetchedResultsController.delegate = self

    return fetchedResultsController
}()

@IBAction func didTouchUpInsideFilterButton(sender: UIBarButtonItem) {

    let alertController = UIAlertController(title: "Filter By:", message: "", preferredStyle: .ActionSheet)

    let nameAction = UIAlertAction(title: "Name", style: .Default) { (UIAlertAction) -> Void in
      NSUserDefaults.standardUserDefaults().setObject("name", forKey: "filterType")

        do {
            try self.fetchResultController.performFetch()
        } catch {
            let fetchError = error as NSError
            print("\(fetchError), \(fetchError.userInfo)")
        }
    };

    let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel) { (UIAlertAction) -> Void in

        self.dismissViewControllerAnimated(true, completion: nil)
    };

    alertController.addAction(nameAction)

    alertController.addAction(cancelAction)

    self.presentViewController(alertController, animated: true, completion: nil)
}

In the alertAction completion block after calling try self.fetchResultController.performFetch() method fetchResultController is not called again to update the predicate.

Please find a solution.


Solution

  • The chunk of code following the declaration of fetchResultController is for property initialization, and will only be run exactly one time, the first time the property is used. That means that that chunk of code that sets the predicate, etc., will not run when didTouchUpInsideFilterButton is called (unless that reference to self.fetchResultController is the first time fetchResultController is used, which seems unlikely).

    You need to explicitly change fetchResultController outside of the initializer when you want to update it.