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.

You may also like,

This page was last edited on September 14th, 2020, at 6:56.


Have an App Idea?

Get your free consultation now

Leave a Reply

Your email address will not be published. Required fields are marked *