Mobile Development

Core Data

In addition to configuration settings found in Local Storage and dynamic file saving, iOS provides a powerful database engine to use within your mobile apps. Welcome to Core Data.

[Core Data] allows data organised by the relational entity–attribute model to be serialised into XML, binary, or SQLite stores. ... Core Data interfaces directly with SQLite, insulating the developer from the underlying SQL [1]

In a basic form, iOS will be creating a file on disk, called the database. iOS will manage creating, opening, writing to and reading to that file. In order to do so efficiently, quickly and without risking a loss of data, we have an abstracted layer on top of this file management layer. Core Data is that abstract layer.

The ObjC blog [12] created graph of a simple Core Data setup:

Definitions

To frame our discussion, let's discuss terms used when implementing Core Data:

  • NSEntityDescription - Describes an entity (also konwn as table) in Core Data. Main container for a set of information.
  • NSFetchedResultsController - Manages the results returned from a Core Data fetch request to provide data for a UITableView object. [5]
  • NSFetchRequest - Describes search criteria used to retrieve data from a persistent store. [6]
  • NSManagedObject - A class that implements all the basic behavior required of a Core Data model object [7]
  • NSManagedObjectContext - Represents a single “object space” or scratch pad in an application. Its primary responsibility is to manage a collection of managed objects. [8]
  • NSPersistentStore - An abstract base class for all Core Data persistent stores, will typically represent a SQLite database for our discussions. [9]
  • NSPersistentStoreCoordinator - Associate persistent stores with a model and serve to mediate between the persistent store and the managed object context. [10]
  • NSSortDescriptor - Defines the sorting mechanism for a set of objects.

    Describes a basis for ordering objects by specifying the property to use to compare the objects, the method to use to compare the properties, and whether the comparison should be ascending or descending. [11]

Let's move on by working with Core Data in Xcode.

Project templates

Grasping Core Data takes time. Luckily, Apple makes it easy to begin by providing project templates that include all necessary pieces you need to begin working with Core Data. Just make sure to have the "Use Core Data" checkbox selected. Xcode will provide some boiler plate code to get you setup.

Before we dive to deep, let's watch this video, which introduces the concept of Core Data:

[Video] Swift Tutorial - Core Data

CoreData with Swift

http://www.youtube.com/watch?v=3IDfgATVqHw

Tools

Xcode provides a Data Model view to manage core data objects. Selecting on the provided *.xcdatamodeld file opens the Data Model view in Xcode.

The steps listed in the above graphic are generally the steps you use on a new Core Data app. Note, we are using the Table View (as pictured).

  1. Define a model
  2. Add a set of attributes to that model
  3. Name each attribute accordingly
  4. Define each attribute with an appropriate type
  5. Switch the editor style over to Graph to view the result

The result of the above steps is then:

We use this Graph view as a visual representation of the Table View, pictured on the previous step.

Code

iOS provides quite a bit of boiler plate code for you to use in your application. We will go over some additional code snippets to perform specific operations on the model object we created above.

The entity we will be using is the following:

Net we will generate a model object file from the Data Model view. We did this by selecting on the model, then clicking New File -> NSManagedObject subclass.

This is the House model object we've generated:

import Foundation
import CoreData

class House: NSManagedObject {

    @NSManaged var yearBuilt: NSNumber
    @NSManaged var streetAddress: String
    @NSManaged var city: String
    @NSManaged var state: String
    @NSManaged var zip: String
    @NSManaged var country: String
    @NSManaged var purchasePrice: NSNumber
    @NSManaged var purchaseDate: NSDate
    @NSManaged var houseID: String
}

We will show our methods to manage the data in the next few code snippets.

Utility Class

import UIKit
import CoreData

class TestingUtility: NSObject {

    private var houseModels = Array<House>()
    private var appDelegate = UIApplication.sharedApplication().delegate as AppDelegate

    // We will be adding methods starting here
}

Reading rows from the entity

The first function we will add is to retrieve all model objects into an array. We wil use this array as a property on the class.

    func retreveAllHouseObjects() {
        let fetchRequest = NSFetchRequest(entityName: "House")
        let sortDescriptor = NSSortDescriptor(key: "PurchasePrice", ascending: true)
        fetchRequest.sortDescriptors = [sortDescriptor]

        if let fetchResults = appDelegate.managedObjectContext!.executeFetchRequest(fetchRequest, error: nil) as? [House] {
            houseModels = fetchResults
        }
    }

Adding a entry to a entity

Our next function adds a entry into our House entity.

    func addHouseObject(purchasePrice: Double, street: String, city: String, state: String, zip: String, purchaseDate: NSDate) {

        let newHouse = NSEntityDescription.insertNewObjectForEntityForName("House", inManagedObjectContext: appDelegate.managedObjectContext!) as House
        newHouse.purchasePrice = NSNumber(double: purchasePrice)
        newHouse.streetAddress = street
        newHouse.city = city
        newHouse.state = state
        newHouse.zip = zip
        newHouse.purchaseDate = purchaseDate
        newHouse.houseID = NSUUID().UUIDString

        appDelegate.saveContext()
    }

Updating an entity

Our next function edits the purchase price of a particular house. Notice that we are using a houseID string to reference the house we will be wanting to update. Our database is configured to guarantee that only one entry exists per house ID.

    func updateHouseObject(houseID: String, purchasePrice: Double) {
        let housesToUpdate = houseModels.filter({$0.houseID == houseID})
        if housesToUpdate.count > 0 {
            let house = housesToUpdate[0]
            house.purchasePrice = purchasePrice
            appDelegate.saveContext()
        }
    }

Deleting a entry from an entity

Last, let's show the code necessary to delete a house object. This is similar to how we setup update, in that we will be using a unique houseID to find our house object, and then delete it.

    func deleteHouseObject(houseID: String) {
        let housesToDelete = houseModels.filter({$0.houseID == houseID})
        if housesToDelete.count > 0 {
            let house = housesToDelete[0]
            appDelegate.managedObjectContext!.deleteObject(house)
        }
    }

With practice, Core Data can be mastered. Check out the following tutorials which will help expand our above examples with completed code projects.

Tutorials

  1. Tutorial 1 - Core Data in Swift: http://jamesonquave.com/blog/core-data-in-swift-tutorial-part-1/
  2. Tutorial 2 - Your First Core Data App with Swift: http://www.raywenderlich.com/85578/first-core-data-app-using-swift

Advanced

Once you can read and write to Core Data from within your app, go ahead and explore the following topics.

Relationships

One of the features of a database is the ability to relate objects to each other. For example, houses have owners. A particular owner may have multiple properties.

For more on relationships between entities, check out the Core Data Programming Guide - Relationships and Fetched Properties: https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/CoreData/HowManagedObjectsarerelated.html

Model Revisions

After deploying your app, a new version may require an update to your Core Data model. If that is the case, iOS requires that you generate a model revision. This will provide an automatic path for current users of your app to upgrade into the new model.

For more information on creating model revisions and an upgrade path for your users, check out the Core Data Model Versioning and Data Migration Programming Guide here: https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreDataVersioning/Articles/Introduction.html

Core Data Conceptual Overview

ObjC provides a very good conceptual overivew of Core Data an its internal workings here: http://www.objc.io/issue-4/core-data-overview.html

References

[1] Core Data - http://en.wikipedia.org/wiki/Core_Data

[2] Core Data Programming Guide - https://developer.apple.com/library/watchos/documentation/Cocoa/Conceptual/CoreData/index.html

[3] Using a Managed Object Model - https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/CoreData/KeyConcepts.html

[4] Creating and Deleting Managed Objects - https://developer.apple.com/library/mac/documentation/DataManagement/Conceptual/CoreDataSnippets/Articles/creating.html

[5] NSFetchedResultsController - https://developer.apple.com/library/ios/documentation/CoreData/Reference/NSFetchedResultsController_Class/

[6] NSFetchRequest - https://developer.apple.com/library/mac/documentation/Cocoa/Reference/CoreDataFramework/Classes/NSFetchRequest_Class/index.html

[7] NSManagedObject - https://developer.apple.com/library/ios/documentation/Cocoa/Reference/CoreDataFramework/Classes/NSManagedObject_Class/index.html

[8] NSManagedObjectContext - https://developer.apple.com/library/ios/documentation/Cocoa/Reference/CoreDataFramework/Classes/NSManagedObjectContext_Class/index.html

[9] NSPersistentStore - https://developer.apple.com/library/ios/documentation/Cocoa/Reference/NSPersistentStore_Class/index.html

[10] NSPersistentStoreCoordinator - https://developer.apple.com/library/mac/documentation/Cocoa/Reference/CoreDataFramework/Classes/NSPersistentStoreCoordinator_Class/index.html

[11] NSSortDescriptor - https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSSortDescriptor_Class/index.html

[12] ObjC - Core Data Overview http://www.objc.io/issue-4/core-data-overview.html