NSFetchedResultsController Tutorial: The Easiest Way to Manage Data

If you have heard about NSFetchedResultsController Class for the first time, it is a class with which you can optimize your iOS app to improve response time and reduce the memory overhead.

Presently, most of the developers load all of the FailedBanksInfo objects from the database into memory at once. It is fine and good for the app, but when you’ll have the complex amount of data to load, this process will be slower and it could have a detrimental impact on the users. And, this is where the NSFetchedResultsController class comes to the picture!

Why NSFetchedResultsController Class?

You can easily add it with the Core Data which dramatically improves the performance.

In this tutorial, we’re going to guide you how you can use NSFetchedResultsController class including NSFetchRequest example.

  1. 👉 Create an App “SOCoreDataDemo” and select “Use Core Data” during this process.




  2. 👉 It will create .xcdatamodeld file in app and you can see “Core Data Stack” code in “AppDelegate”


  3. 👉 Go to SOCoreDataDemo.xcdatamodeld and create an Entity.




  4. 👉 Now right click on “SOCoreDataDemo” folder and click on “New File” and choose template from “Core Data” -> “NSManagedObject subclass”


  5. 👉 Then follow one by one steps, in the end of that you will get two model classes which contain Entity name like (“Student+CoreDataProperties.swift” and “Student.swift”)


  6. 👉 To import core data, add import statement

    import UIKit
    import CoreData
  7. 👉 Add the NSFetchedResultsControllerDelegate protocol to your class.

  8. 👉 Create object of “NSFetchedResultsController” and “NSManagedObjectContext” in “ViewController.swift”

    //Mark: - Properties
    var fetchedResultsController: NSFetchedResultsController!
    lazy var context: NSManagedObjectContext = {
    let appDel:AppDelegate = (UIApplication.sharedApplication().delegate as! AppDelegate)
    return appDel.managedObjectContext
  9. 👉 Add new entry in core data

    //Add new entry in core data
    let entity = NSEntityDescription.entityForName("Student", inManagedObjectContext:context)
    let newStudent = Student(entity:entity!, insertIntoManagedObjectContext:context)
    newStudent.first_name = txtFirstName.text
    newStudent.last_name = txtLastName.text
    if let number = Int(txtRollNo.text!) {
    let myRollNo = NSNumber(integer:number)
    newStudent.rollno = myRollNo
    } else {
    print("'\(txtRollNo.text!)' did not convert to an Int")
    do {
    try self.context.save()
    } catch let error as NSError {
    print("Error saving movie \(error.localizedDescription)")
  10. 👉 Now, fetch Student Record from Core Data

    //Fetch Student List
    func fetchAllStudentList() {
    let fetchRequest = NSFetchRequest(entityName: "Student")
    let fetchSort = NSSortDescriptor(key: "rollno", ascending: true)
    fetchRequest.sortDescriptors = [fetchSort]
    fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
    fetchedResultsController.delegate = self
    do {
    try fetchedResultsController.performFetch()
    } catch let error as NSError {
    print("Unable to perform fetch: \(error.localizedDescription)")
  11. 👉 Show list in table//Show list of student

    //MARK: UITableViewDelegate
    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return 44
    //MARK: UITableViewDataSource
    //Number of section
    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    guard let sectionCount = fetchedResultsController.sections?.count else {
    return 0
    return sectionCount
    //Number of section in row
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    guard let sectionData = fetchedResultsController.sections?[section] else {
    return 0
    return sectionData.numberOfObjects
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
    configureCell(cell, forRowAtIndexPath: indexPath)
    return cell
    func configureCell(cell: UITableViewCell, forRowAtIndexPath: NSIndexPath) {
    let student = fetchedResultsController.objectAtIndexPath(forRowAtIndexPath) as! Student
    cell.textLabel?.text = student.valueForKey("first_name") as? String
  12. 👉 Delete entry from core data

    //Delete from core data
    func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
    // Return NO if you do not want the specified item to be editable.
    return true
    func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
    switch editingStyle {
    case .Delete:
    let student = fetchedResultsController.objectAtIndexPath(indexPath) as! Student
    do {
    try context.save()
    } catch let error as NSError {
    print("Error saving context after delete: \(error.localizedDescription)")
  13. 👉 When the content will be change then delegate will notify and delegate of FetchedResultsController will be called.

    // MARK: - FetchedResultsController Delegate
    func controllerWillChangeContent(controller: NSFetchedResultsController) {
    func controllerDidChangeContent(controller: NSFetchedResultsController) {

    You just put tableView.reloadData() in “controllerDidChangeContent” and your data will be updated.

    You can also use tableView.beginUpdates() in “controllerWillChangeContent” and tableView.endUpdates() in “controllerDidChangeContent”. Using this you can show animation during changes in the table.

  14. 👉 Further, we add two more delegate methods for update section of tableView and update rows of the section in a table view.

    func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) {
    // 1
    switch type {
    case .Insert:
    tableView.insertSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Automatic)
    case .Delete:
    tableView.deleteSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Automatic)
    default: break
    func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
    // 2
    switch type {
    case .Insert:
    tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Automatic)
    case .Delete:
    tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Automatic)
    default: break

    Once, after completing all the steps, when you compile and run your project, you’ll see the same thing, but if you examine the debug output, you’ll see something different in the behind the scenes.

    The NSFetchedResultsController class of your project is getting a list of IDs from FailedBankInfo in a sorted order and when the user goes through the table, it’ll load one batch at a time, rather than loading the entire database of objects into memory at once. This is how Core Data can save plenty of time and increase the performance.

    You can get the same project here.

    So, if you want to fetch the big amount of data easily, hire iPhone app developer from Space-O Technologies and let the professionals take care of the rest.

Author Bio
Hitesh Trivedi
Hitesh Trivedi
Designation: iOS Team Lead

Hitesh Trivedi is an iOS Team Lead at Space-O Technologies. He has over 10 years of experience in iOS app development. He has guided to develop over 100 iPhone apps with unique features and functionalities. He has special expertise in Swift and Objective-C.