





















































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:
Next, there are two concepts that you need to know, and they are:
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:
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:
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.
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:
Let's get started with our code examples:
@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext; @property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel; @property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
- (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.
In this article, you learned about Core Data and why you should use it.
Further resources on this subject: