NSFetchedResultsController Tutorial: The Easiest Way to Manage Data

0
Shares
NSFetchedResultsController Tutorial: The Easiest Way to Manage Data
5 (100%) 1 vote

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.

Steps

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

CoreData1

 

CoreData2

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

CoreData3

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

CoreData4

 

CoreData7

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

CoreData8

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”)

CoreData13

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 {
//1
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) {
//1
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
context.deleteObject(student)
do {
try context.save()
} catch let error as NSError {
print("Error saving context after delete: \(error.localizedDescription)")
}
default:break
}
}

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) {
tableView.beginUpdates()
}

func controllerDidChangeContent(controller: NSFetchedResultsController) {
tableView.endUpdates()
}

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.

 
0
Shares
 

LET'S TALK VALIDATE YOUR IDEA!