9 min read

In this article by Gibson Tang and Maxim Vasilkov, authors of the book Objective-C Memory Management Essentials, you will learn what Core Data is and why you should use it.

(For more resources related to this topic, see here.)

Core Data allows you to store your data in a variety of storage types. So, if you want to use other types of memory store, such as XML or binary store, you can use the following store types:

  • NSSQLiteStoreType: This is the option you most commonly use as it just stores your database in a SQLite database.
  • NSXMLStoreType: This will store your data in an XML file, which is slower, but you can open the XML file and it will be human readable. This has the option of helping you debug errors relating to storage of data. However, do note that this storage type is only available for Mac OS X.
  • NSBinaryStoreType: This occupies the least amount of space and also produces the fastest speed as it stores all data as a binary file, but the entire database binary need to be able to fit into memory in order to work properly.
  • NSInMemoryStoreType: This stores all data in memory and provides the fastest access speed. However, the size of your database to be saved cannot exceed the available free space in memory since the data is stored in memory. However, do note that memory storage is ephemeral and is not stored permanently to disk.

Next, there are two concepts that you need to know, and they are:

  • Entity
  • Attributes

Now, these terms may be foreign to you. However, for those of you who have knowledge of databases, you will know it as tables and columns. So, to put it in an easy-to-understand picture, think of Core Data entities as your database tables and Core Data attributes as your database columns.

So, Core Data handles data persistence using the concepts of entity and attributes, which are abstract data types, and actually saving the data into plists, SQLite databases, or even XML files (applicable only to the Mac OS). Going back a bit in time, Core Data is a descendant of Apple’s Enterprise Objects Framework (EOF) , which was introduced by NeXT, Inc in 1994, and EOF is an Object-relational mapper (ORM), but Core Data itself is not an ORM. Core Data is a framework for managing the object graph, and one of it’s powerful capabilities is that it allows you to work with extremely large datasets and object instances that normally would not fit into memory by putting objects in and out of memory when necessary. Core Data will map the Objective-C data type to the related data types, such as string, date, and integer, which will be represented by NSString, NSDate, and NSNumber respectively. So, as you can see, Core Data is not a radically new concept that you need to learn as it is grounded in the simple database concepts that we all know. Since entity and attributes are abstract data types, you cannot access them directly as they do not exist in physical terms. So to access them, you need to use the Core Data classes and methods provided by Apple.

The number of classes for Core Data is actually pretty long, and you won’t be using all of them regularly. So, here is a list of the more commonly used classes:

CLASS NAME

EXAMPLE USE CASE

NSManagedObject

Accessing attributes and rows of data

NSManagedObjectContext

Fetching data and saving data

NSManagedObjectModel

Storage

NSFetchRequest

Requesting data

NSPersistentStoreCoordinator

Persisting data

NSPredicate

Data query

Now, let’s go in-depth into the description of each of these classes:

  • NSManagedObject: This is a record that you will use and perform operations on and all entities will extend this class.
  • NSManagedObjectContext: This can be thought of as an intelligent scratchpad where temporary copies are brought into it after you fetch objects from the persistent store. So, any modifications done in this intelligent scratchpad are not saved until you save those changes into the persistent store, NSManagedObjectModel. Think of this as a collection of entities or a database schema, if you will.
  • NSFetchRequest: This is an operation that describes the search criteria, which you will use to retrieve data from the persistent store, a kind of the common SQL query that most developers are familiar with. NSPersistentStoreCoordinator: This is like the glue that associates your managed object context and persistent.
  • NSPersistentStoreCoordinator: Without this, your modifications will not be saved to the persistent store.
  • NSPredicate: This is used to define logical conditions used in a search or for filtering in-memory. Basically, it means that NSPredicate is used to specify how data is to be fetched or filtered and you can use it together with NSFetchRequest as NSFetchRequest has a predicate property.

Putting it into practice

Now that we have covered the basics of Core Data, let’s proceed with some code examples of how to use Core Data, where we use Core Data to store customer details in a Customer table and the information we want to store are:

  • name
  • email
  • phone_number
  • address
  • age

Do note that all attribute names must be in lowercase and have no spaces in them. For example, we will use Core Data to store customer details mentioned earlier as well as retrieve, update, and delete the customer records using the Core Data framework and methods.

  1. First, we will select File | New | File and then select iOS | Core Data:

    Objective-C Memory Management Essentials

  2. Then, we will proceed to create a new Entity called Customer by clicking on the Add Entity button on the bottom left of the screen, as shown here:

    Objective-C Memory Management Essentials

  3. Then, we will proceed to add in the attributes for our Customer entity and give them the appropriate Type, which can be String for attributes such as name or address and Integer 16 for age.

    Objective-C Memory Management Essentials

  4. Lastly, we need to add CoreData.framework, as seen in the following screenshot:

    Objective-C Memory Management Essentials

  5. So with this, we have created a Core Data model class consisting of a Customer entity and some attributes. Do note that all core model classes have the .xcdatamodeld file extension and for us, we can save our Core Data model as Model.xcdatamodeld.
  6. Next, we will create a sample application that uses Core Data in the following ways:
    •     Saving a record
    •     Searching for a record
    •     Deleting a record
    •     Loading records

Now, I won’t cover the usage of UIKit and storyboard, but instead focus on the core code needed to give you an example of Core Data works. So, to start things off, here are a few images of the application for you to have a feel of what we will do:

  1. This is the main screen when you start the app:

    Objective-C Memory Management Essentials

  2. The screen to insert record is shown here:

    Objective-C Memory Management Essentials

  3. The screen to list all records from our persistent store is as follows:

    Objective-C Memory Management Essentials

  4. By deleting a record from the persistent store, you will get the following output:

    Objective-C Memory Management Essentials

Getting into the code

Let’s get started with our code examples:

  1. For our code, we will first declare some Core Data objects in our AppDelegate class inside our AppDelegate.h file such as:
    @property (readonly, strong, nonatomic)
    NSManagedObjectContext
    *managedObjectContext;
    @property (readonly, strong, nonatomic)
    NSManagedObjectModel
    *managedObjectModel;
    @property (readonly, strong, nonatomic)
    NSPersistentStoreCoordinator
    *persistentStoreCoordinator;
  2. Next, we will declare the code for each of the objects in AppDelegate.m such as the following lines of code that will create an instance of NSManagedObjectContext and return an existing instance if the instance already exists. This is important as you want only one instance of the context to be present to avoid conflicting access to the context:
    - (NSManagedObjectContext *)managedObjectContext
    {
    if (_managedObjectContext != nil) {
    return _managedObjectContext;
    }
    NSPersistentStoreCoordinator *coordinator = [self
    persistentStoreCoordinator];
    if (coordinator != nil) {
    _managedObjectContext = [[NSManagedObjectContext
    alloc] init];
    [_managedObjectContext
    setPersistentStoreCoordinator:coordinator];
    }
    if (_managedObjectContext == nil)
    NSLog(@"_managedObjectContext is nil");
    return _managedObjectContext;
    }

    This method will create the NSManagedObjectModel instance and then return the instance, but it will return an existing NSManagedObjectModel if it already exists:

    // Returns the managed object model for the application.
    - (NSManagedObjectModel *)managedObjectModel
    {
    if (_managedObjectModel != nil) {
    return _managedObjectModel;//return model since it
    already exists
    }
    //else create the model and return it
    //CustomerModel is the filename of your *.xcdatamodeld
    file
    NSURL *modelURL = [[NSBundle mainBundle]
    URLForResource:@"CustomerModel" withExtension:@"momd"];
    _managedObjectModel = [[NSManagedObjectModel alloc]
    initWithContentsOfURL:modelURL];
    if (_managedObjectModel == nil)
    NSLog(@"_managedObjectModel is nil");
    return _managedObjectModel;
    }

    This method will create an instance of the NSPersistentStoreCoordinator class if it does not exist, and also return an existing instance if it already exists. We will also put some logging via NSLog to tell the user if the instance of NSPersistentStoreCoordinator is nil and use the NSSQLiteStoreType keyword to signify to the system that we intend to store the data in a SQLite database:

    // Returns the persistent store coordinator for the
    application.
    - (NSPersistentStoreCoordinator
    *)persistentStoreCoordinator
    { NSPersistentStoreCoordinator
    if (_persistentStoreCoordinator != nil) {
    return _persistentStoreCoordinator;//return
    persistent store
    }//coordinator since it already exists
    NSURL *storeURL = [[self applicationDocumentsDirectory]
    URLByAppendingPathComponent:@"CustomerModel.sqlite"];
    NSError *error = nil;
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator
    alloc]
    initWithManagedObjectModel:[self managedObjectModel]];
    if (_persistentStoreCoordinator == nil)
    NSLog(@"_persistentStoreCoordinator is nil");
    if (![_persistentStoreCoordinator addPersistentStoreWithTy
    pe:NSSQLiteStoreType configuration:nil URL:storeURL options:nil
    error:&error]) {
    NSLog(@"Error %@, %@", error, [error userInfo]);
    abort();
    }
    return _persistentStoreCoordinator;
    }

    The following lines of code will return a URL of the location to store your data on the device:

    #pragma mark - Application's Documents directory// Returns
    the URL to the application's Documents directory.
    - (NSURL *)applicationDocumentsDirectory
    {
    return [[[NSFileManager defaultManager]
    URLsForDirectory:NSDocumentDirectory
    inDomains:NSUserDomainMask] lastObject];
    }

    As you can see, what we have done is to check whether the objects such as _managedObjectModel are nil and if it is not nil, then we return the object, else we will create the object and then return it. This concept is exactly the same concept of lazy loading. We apply the same methodology to managedObjectContext and persistentStoreCoordinator. We did this so that we know that we only have one instance of managedObjectModel, managedObjectContext, and persistentStoreCoordinator created and present at any given time. This is to help us avoid having multiple copies of these objects, which will increase the chance of a memory leak.

    Note that memory management is still a real issue in the post-ARC world. So what we have done is follow best practices that will help us avoid memory leaks.

In the example code that was shown, we adopted a structure so that only one instance of managedObjectModel, managedObjectContext and persistentStoreCoordinator is available at any given time.

Next, let’s move on to showing you how to store data into our persistent store. As you can see in the preceding screenshot, we have fields such as name, age, address, email, and phone_number, which corresponds to the appropriate fields in our Customer entity.

Summary

In this article, you learned about Core Data and why you should use it.

Resources for Article:


Further resources on this subject:


LEAVE A REPLY

Please enter your comment!
Please enter your name here