|Read more about this book|
(For more resources on this subject, see here.)
Core Data is Apple's persistence framework, which is used to persist—store our application's data in a persistent store, which may be memory or a flat file database. It helps us represent our data model in terms of an object graph, establish relationships among objects, and it can also store object graphs on the disk. It also allows us to use the entities of our data model in the form of objects, that is, it maps our data into a form that can be easily stored in a database, such as SQLite, or into a flat file. Also, the Core Data reduces a lot of coding. On using Xcode's templates for Core Data applications, we automatically get the boilerplate code that does several complex tasks such as generating XML files, binary files, SQLite files automatically for us without writing a single code, allowing us to focus on the business logic of our application.
Besides this, Core Data also provides several features that are required in data manipulation, which includes filtering data, querying data, sorting data, establishing relationships with other data, and persisting data in different repositories.
Core Data features
The Core Data framework provides lots of features that include the following:
- Supports migrating and versioning: It means we can modify our data model, that is, entities of the application, whenever desired. The Core Data will replace the older persistent store with the revised data model.
- Supports Key-Value Coding (KVC): It is used to store and retrieve data from the managed objects. Core Data provides the methods required for setting and retrieving attribute values from the managed object, respectively. We will be using this feature in our application to display the information of customers and the products sold to them through the table view.
- Tracks the modifications: Core Data keeps track of the modifications performed on managed objects thus allowing us to undo any changes if required. We will be using this feature in our application while modifying the information of a customer or product to know what the earlier value was and what the new value entered for it is.
- Supports lazy loading: It's a situation that arises when all the property values of a managed object are not loaded from the data store and the property values are accessed by the application. In such situations, faulting occurs and the data is retrieved from the store automatically.
- Efficient database retrievals: Core Data queries are optimized for this, though the execution of query is dependent on the data store.
- Multi-threading: Core Data supports multi-threading in an application, that is, more than one thread can be executed in parallel to increase performance. Even some tasks can be performed in the background using a separate thread.
- Inverse relationship: Core Data maintains an inverse relationship for consistency. If we add an object to a relationship, Core Data will automatically take care of adding the correct object to the inverse relationship. Also, if we remove an object from a relationship, Core Data will automatically remove it from the inverse relationship. In our application, we will be using an inverse relationship between the Customer and Product entities, so that if a customer is deleted, the information of all the products purchased by him/her should also be automatically deleted.
- External data repositories: Core Data supports storing objects in external data repositories in different formats.
Core Data describes the data in terms of a data model. A data model is used to define the structure of the data in terms of entities, properties, and their relationships.
Because Core Data maintains data in terms of objects, an entity is an individual data object to represent complete information of the person, item, object, and so on. For example, customer is an entity, which represents information of customers, such as name, address, e-mail ID, contact number, products purchased, date of purchase, and so on. Similarly, the product is an entity, which represents the information of a product, such as name of the product, price, weight, and so on. An entity consists of properties that are a combination of attributes and relationships. An entity in Xcode's Data Model Editor may appear as shown in the following screenshot:
Properties of an entity give detailed information about it, such as what are its attributes and how it is related to other entities. A property of an entity refers to its attributes and relationships. Attributes are scalar values and relationships are pointers to or collections of other entities at the object level. A property is represented by a name and a type.
Attributes are the variables within an object (entity). In fact, a collection of attributes makes an entity. In database language, they are known as columns of the table. For example, the customer's entity may consist of attributes such as name, address, contact number, items purchased, and so on. Similarly, the attributes in the products table may be item code, item name, quantity, and so on. While creating attributes of an entity, we have to specify its name and its data type to declare the kind of information (whether integer, float, string, and so on) that will be stored in the attribute. Also, we can define the constraints on the information that can be stored in the column. For example, we can specify the maximum, minimum value (range) that can be stored in that attribute, or whether the attribute can or cannot store certain special symbols, and so on. Also, we can specify the default value of an attribute.
Besides attributes, an entity may also contain relationships (which define how an entity is related to other entities). The attributes and relationships of an entity are collectively known as properties. The relationships are of many types (To-One, To-Many, and Many-to-Many) and play a major role in defining connection among the entities and what will be the impact of insertion or deletion of a row in one entity on the connected entities.
Examples of relationship types:
- The relationship from a child entity to a parent entity is a To-One relationship as a child can have only one parent
- The relationship from a customer to a product entity is a To-Many relationship as a customer can purchase several products
- The relationship from an employee to a project entity is of Many-to-Many type as several employees can work on one project and an employee can work on several projects simultaneously
To define a many-to-many relationship in Core Data, we have to use two To-many relationships. The first To-many relationship is set from the first entity to the second entity. The second To-many relationship is set from the second entity to the first entity.
In Xcode's Data Model Editor, the relationship from Customer to Product—a To-Many relationship—is represented by a line that appears pointing from the Customer entity to the Product entity with two arrows, (designating a One-to-Many relationship) as shown in the subsequent screenshot, whereas the To-One relationship is represented by a line with a single arrow:
When defining relationships in Core Data we may use inverse relationships, though it's optional.
In Core Data, every relationship can have an inverse relationship. Like, if there is a relationship from Customer to Product, there will be a relationship from Product to Customer too. A relationship does not need to be the same kind as its inverse; for example, a To-One relationship can have an inverse relationship of type To-Many. Although relationships are not required to have an inverse, Apple generally recommends that you always create and specify the inverse, (even if you won't need) as it helps Core Data to ensure data integrity.
For example, consider a situation when a Customer entity has a relationship of the To-Many type to a Product entity and some information of a customer is changed or a row of a customer is deleted. Then it will be easier for Core Data to ensure consistency; that is, by inverse relationship, Core Data can automatically find the products related to the deleted customer and hence, delete them too.
Before we go further, let us have a quick look at the architecture that is used in iPhone application development: MVC.
Model View Controller (MVC)
iPhone application development uses MVC architecture where M stands for Model, V stands for View, and C for Controller.
- Model represents the backend data—data model
- View represents the user interface elements through which the user looks at the contents displayed by the application and can interact with them
- Controller represents the application logic that decides the type of view to be displayed on the basis of actions taken by the user
Core Data organizes the data model in terms of objects that are easy to handle and manipulate. The finalized objects are stored on a persistent storage. The usual way of representing data models is through classes that contains variables and accessor methods. We don't have to create classes by hand, (for our data models) as Core Data framework provides a special Data Model Design tool (also known as Data Model Editor) for quickly creating an entity relationship model. The terms that we will be frequently using from now onwards are Managed Object Model, Managed Objects, and Managed Object Context. Let us see what these terms mean:
- Managed Object Model: The data model created by the Data Model Design tool (Data Model Editor) is also known as Managed Object Model.
- Managed Objects: Managed objects are instances of the NSManagedObject class (or its subclass) that represent instances of an entity that are maintained (managed) by the Core Data framework. In a managed object model, an entity is defined by an entity name and the name of the class that is used at runtime to represent it. The NSManagedObject class implements all of the functionality required by a managed object.
- A managed object is associated with an entity description (an instance of NSEntityDescription) that describes the object; for example, the name of the entity, its attributes, relationships, and so on. In other words, an NSEntityDescription object may consist of NSAttributeDescription and NSRelationshipDescription objects that represent the properties of the entity. At runtime, the managed object is associated with a managed object context.
- Managed Object Context: The objects when fetched from the persistent storage are placed in managed object context. It performs validations and keeps track of the changes made to the object's attributes so that undo and redo operations can be applied to it, if required. In a given context, a managed object provides a representation of a record in a persistent store. Depending on a situation, there may be multiple contexts—each containing a separate managed object representing that record.
All managed objects are registered with managed object context.
For an application, we need the information represented by the Managed Object (instance of an entity) to be stored on the disk (persistent store) via managed object context. To understand the concepts of managed object context and its relation with data persistence, we need to understand the components of Core Data API, so let us go ahead and look at what Core Data API is all about.
Core Data API
The Core Data API, also called the stack, consists of three main components:
The PersistentStoreCoordinator plays a major role in storing and retrieving managed objects from the Persistent Store via ManagedObjectContext. We can see in the following figure how the three are related:
The Managed Object Model (an instance of NSManagedObjectModel class) is created from the data model of our application. If there is more than one data model in our application, the Managed Object Model is created by merging all of the data models found in the application bundle. The managed object (instance of the NSManagedObject class or its subclass) represents an instance of an entity that is maintained (managed) by the Core Data framework. A managed object is an instance of an Objective-C class, but it differs from other objects in three main ways:
- A managed object must be an instance of NSManagedObject or of a class that inherits from NSManagedObject
- The state of managed object is maintained by its managed object context
- A managed object has an associated entity description that describes the properties of the object
For working with a managed object, it is loaded into memory. The managed object context maintains the state of the managed object after it is loaded in memory. The Managed Object Context tracks in-memory changes that have yet to be persisted to the data store. Any changes made to the state of an NSManagedObject do actually affect the state of the object in memory, not just the persistent representation of that object in the data store. When we want to commit the modifications made to the managed object, we save the managed object context to the persistent store. In order to deal with persistent store, the managed object context needs a reference to a PersistentStoreCoordinator. In other words, a pointer to the PersistentStoreCoordinator is required for creating a Managed Object Context. Remember, the PersistentStoreCoordinator is the essential middle layer in the stack that helps in storing and retrieving the managed object model from the persistent store.
The managed object context is an object that plays a major role in the life cycle of managed objects. It handles all the aspects of managed object from faulting to validation including undo/redo. To modify managed objects, they are fetched from a persistent store through managed context. The modified managed objects are committed to the persistent store through context only. The managed objects represent data held in a persistent store. Faulting is considered to occur for an object whose property values have not yet been loaded from the external data store.
To access the objects (entity) in managed object context, FetchRequest, an instance of NSFetchRequest class, is used. To define the entity to be retrieved via NSFetchRequest, we pass the appropriate NSEntityDescription to the NSFetchRequest.
The result, that is, the set of entities retrieved from the managed object context (on the basis of FetchRequest) are managed by FetchedResultsController—an instance of NSFetchedResultsController.
In fact, FetchRequest is passed to the FetchedResultsController along with a reference to the managed object context. Once the NSFetchedResultsController class has been initialized, we can perform a fetch operation to load the entities (stored in it) into memory.
The managed object context keeps track of all the changes made to the managed object since the last time it was loaded in memory and hence helps in undoing any changes made to the managed object (if required).The Persistent Store Coordinator helps in avoiding redundancy if multiple calls are made by different classes on the same file at the same time, that is, the multiple calls are serialized by the NSPersistentStoreCoordinator class to avoid redundancy.
Let us now get a detailed understanding of the terms used above.
|Read more about this book|
(For more resources on this subject, see here.)
Persistent Store is a data store (repository) that handles mapping between data (in the store) and corresponding objects in a managed object context. The managed contexts can be stored in any of the following three formats—In-memory, Binary, and SQLite database format. In other words, the Persistence Store can be of three types—In-memory store, Binary store, and SQLite store.
- The In-memory store is used in caching mechanism
- Binary format stores information in a non-human-readable form but provides better performance
- SQLite database format is scalable and is the fastest
The drawback with the Binary and In-memory store contents is that they have to be entirely loaded in memory at startup and hence consume a lot of memory, whereas the SQLite store can be loaded and unloaded from memory as per requirements. SQLite is an open source embedded database that is highly preferred for Core Data.
A persistent store is associated with a single data model.
Persistent Store Coordinator
The Persistent Store Coordinator is an instance of the NSPersistentSoreCoordinator class that performs co-ordination between managed object contexts and persistent store, that is, it helps in storing and retrieving the managed object model from the Persistent Store. All the calls that require "reads" or "writes" to the Persistent Store are serialized by the Persistent Store Coordinator (so that multiple calls against the same file are not being made at the same time). The Persistent Store Coordinator creates a path to a file (on disk drive) in the Documents directory in our application's sandbox.
FetchRequest is an instance of the NSFetchRequest class and is used to access the objects in managed object context. There are two parts to the creation of an NSFetchRequest:
- Deciding the entity to be retrieved
- Defining an NSPredicate to define the criteria (condition) to retrieve only the desired objects (this part is optional)
To define the entity to be retrieved via NSFetchRequest, we pass the appropriate NSEntityDescription to the NSFetchRequest. Recall that NSEntityDescription consists of the name of the entity, its attributes, relationships, and so on.
When NSFetchRequest is executed against the NSManagedObjectContext, the result may be either in the form of an NSArray (containing the fetched entities) or there may be an error. That is why, the execution of an NSFetchRequest accepts a pointer to an NSError to describe the errors that may occur while execution. If the execution of NSFetchRequest fails, then the pointer will be directed to an instance of NSError that contains the reason of failure. The method signature will be as follows:
NSArray *myArray = [myManagedObjectContext executeFetchRequest:
FetchedResultsController is an instance of the NSFetchedResultsController class and as the name suggests, the NSFetchedResultsController class is meant for managing the result—the set of entities from an NSManagedObjectContext that are retrieved on the basis of FetchRequest. It helps with the following:
- Querying the retrieved result
- Arranging the result
- Notifying UIViewController in case any of the entities in the result set are modified (added, deleted, updated, and so on)
The NSFetchedResultsController requires an NSFetchRequest for its initialization. The NSFetchRequest contains the criteria of the entities that are accessed through the NSFetchedResultsController. The NSFetchRequest is passed to the NSFetchedResultsController along with a reference to the NSManagedObjectContext. Once the NSFetchedResultsController has been initialized, we can perform a fetch operation to load the entities into memory.
We have enough knowledge of Core Data and its different components. Let us see what kind of application we can develop using Core Data.
Overview of the application: Sales Record System for a Departmental Store
We are going to assume the end user of this app is a wholesale dealer who wants to track in-stock product quantities, sales, and customer information. In this application, the user can store and track information about customers, such as names, e-mail IDs, and phone numbers, as well as sales data and product information (name, quantity, price, photo, and inventory). Therefore, the application must store information about:
- Customer information
From now on, we will be referring to a vendor's product as Master Product and an item sold to customers as Product.
Entity Relationship Diagram
Our application consists of three entities:
The Entity Relationship Diagram (ERD) of the application is as shown in the following figure:
Let's have a quick look at the usage of the three entities displayed in the preceding figure:
- The Product table is used to store information about products sold to the selected customer. The table has three fields: itemname, price, and quantity. This table is related to the Customer table via a many-to-one relationship because many customers may purchase the same product.
- The Customer table is used to store information about the customer and has three data fields: name, e-mail ID, and contact number. This table is related to the Product table via a one-to-many relationship because a customer can purchase more than one product.
- The MasterProduct table is used to store information about the vendor's products. This table also shows the quantity on hand for each product. The table has four fields: itemname, price, quantity, and image (photo). This table is not related to any other table and works independently.
An application output sample
Let's take a look at how the application works. When the program is started the initial view will appear, as shown in the following given image (a). The top of the view holds a navigation bar with two bar button items: Edit and +. At the bottom of the view is a toolbar holding a bar button item called Master Product Information. The title in the navigation bar, Customers List, tells us that the two bar button items (Edit and +) are concerned with editing and adding customer information, respectively. The bar button item, Master Product Information, is used to store product data: name, price, quantity, and the product image.
Entering Master Product Information
We begin by entering the product data, Master Product Information, which will include product name, price, quantity on hand, and a product photo. The product quantity is automatically adjusted after a sale.
When Master Product Information is selected, the view appears as shown in preceding image (b). The view contains a toolbar with three bar button item controls—Customers List, Edit, and Add.
The functions of the three bar button item controls are as follows:
- Customers List: This button will take us back to the main view of the application where we can add or edit customer information.
- Edit: This button allows us to edit master product information. However, the button will work only when there actually are products in the database. Assuming at least one master product exists; the Edit button will show a deletion icon on the left of the master product. When the deletion icon on any master product is selected, a Delete button appears on the right for confirmation. When clicked, the master product is removed from the list.
- Add: This button lets us add new master products to the list. It displays a view as shown in the preceding image (c). We have three text fields to fill: Product Name, Price, and Quantity. Below the text fields is a button to add a product photo. When we click on a text field, a keyboard for data entry appears. The keyboard covers the bottom half of the view, and covers the Select Product Image button. So, a method is added to the application that makes the keyboard disappear if the user presses the Return key after entering value in the Quantity text field. After the keyboard has disappeared, our view will appear, as shown in the subsequent image (a).
When the Select Product Image button is tapped, the Image Picker view displays the Photo Albums, as shown in the next image (b). The category Saved Photos is created by us to contain the master product photos. We'll talk about the steps for creating our own photo category later. When the Saved Photos category is selected, we are shown all of the images that we have copied into this category as shown in the next image (c).
Let's select the image that represents a sample product, as shown in the subsequent image (d). We can now save the product information by tapping the Save button in the navigation bar. The Cancel button at the top is used to stop the product addition process.
After the product data has been saved, we are returned to the Master Product list view. We'll now see the product Milk in the table view, as shown in the next image (a). The black > sign is used to navigate to the product's information page, as shown in image (b). Here, we can modify the information of the chosen master product by selecting the Edit button from the navigation bar. Additionally, we can change the product's image by clicking on the Change Product Image button.
Let's add three more products: Chocolate shown in the next given image (a); Eggs shown in image (b); and Bread shown in image (c). And, to keep things simple, let's use 100 as the beginning inventory quantity.
After adding four master products, our table view will look like the subsequent image (a). The master products are automatically sorted in alphabetical order.
Modifying the Master Product
The black > indicates that selecting a product item will take us to the product editing view, as shown in the next image (b). All the text fields showing master product information are in disabled mode; we cannot modify their content until we select the Edit button from the navigation bar. Once the Edit button is clicked, the button text changes to Save, the text fields are enabled, and we can modify the field data. After updating the master product's information, we save the changes by clicking on the Save button. After tapping the Save button, we will be returned to the view displaying the entire Master Products list, shown in the image (a).
Deleting the Master Product
The Edit button in the navigation bar shown in the next image (a) is used to remove an existing Master Product. When the Edit button is selected, a deletion icon appears to the left of each master product, as shown in image (c). Note that the Edit button's text changes to Done, which we'll use once we have finished with the deletion(s).
Selecting the deletion icon on any master product displays a Delete button to reconfirm that we really, really want to remove the item. For example, let's say we want to remove the product named Chocolate from the list. We tap on its deletion icon, which brings up a Delete button, as shown in the following image (a). If we tap this button, Chocolate disappears from the list, as shown in the subsequent image (b). The deletion icon will disappear when the Done button is pressed.
|Read more about this book|
(For more resources on this subject, see here.)
Entering customer information and order details
If we press the + button in the main view—the first view of the application—we'll see a view to enter customer information—name, e-mail address, and phone number—as shown in the next image (a). The information is saved by selecting the Save button from the navigation bar. The Cancel button discards the new entry. After entering information for three customers, the table view will appear as shown in the next image (b). We can see that the customers' names are automatically sorted in alphabetical order. The search bar in the navigation bar can be used to search the desired customer. For example, entering a character C in the search bar will display only those customer names that contain character C as shown in the next given image (c).
The black > to the right of each customer can be used for two purposes:
- To modify a customer's information
- To enter the selected customer's purchases
Deleting customer information
The next given image (a) displays a more specific search on entering more characters in the search bar. We can see that on entering characters Can in the search bar, we get the list of customer names that contain characters Can. We can select the customer name from the table view to edit information or enter the details of purchased products. For example, if we select a customer, say Candace, we'll see her information in the view, as shown in the next image (b). In this view, there are two bar button items—Edit (at the top) and Products Information at the bottom. The Edit button is used to modify customer information and the Products Information button is used to display the view for adding or editing the customer's purchasing data. The Customers List button returns us to the table view displaying the complete list of customers.
If the Edit button in the Customers List view is tapped, a deletion icon appears to the left of the customer's name. The Edit button changes to Done when we are finished editing the data. Tapping the deletion icon of any customer displays a Delete button for confirmation, as shown in the next given image (c). If that button is pressed, the information of the selected customer will be deleted, and pressing Done (from the navigation bar), returns us to the Customer List.
Searching for specific customers
The search bar at the top of the view can be used to search for a particular customer. For example, to search for customer names that contain the character C, we enter C in the search bar. The customer list in the table view will be filtered and only customer names containing C will be displayed. We can make the search more precise by entering more characters in the search bar. For example, if we enter Can, we'll see the customer name(s) containing that set of characters, as shown in the preceding image (a).
Searching and modifying customer information
To modify customer information, we first select a customer. The next view displays the customer's data, as shown in the given image (b). The text fields are initially in disabled mode. To enable the text fields, click on the Edit button from the navigation bar. The Edit button changes to Done, as shown in image (b). Let's change Ben to David and save it by selecting the Done button. The customer names are alphabetically sorted, so we'll now see that David (previously Ben), appears after Candace, as shown in the given image (c).
Entering Customer Sales Information
Let's enter information about products sold to Candace. On selecting her name, we'll see her information being displayed in the view, as shown in the next image (a). At the bottom of the view is the Products Information button, used to add and edit information about the products sold to the selected customer. When we tap this button, we'll see a view with three buttons—Back, Edit, and Add, as shown in the next image (b).
- Back returns us to the view displaying the customer's information (as shown in image(a)).
- Edit is used to delete an entry. This view shows deletion icons to the left of the products sold.
- Add takes us to a view that displays the list of products available for sale, as shown in image (c).
The search bar at the top of the view can be used to search for the desired product. Typing text in the search bar will filter the products and display only those containing the characters typed into the search bar. After a product is selected, its name, price, and image will appear and we will be asked to enter the quantity of the selected product sold to the customer. For example, if we select Bread from the list, we'll be asked to enter its quantity as shown in image (a). Let's suppose that Candace bought three loaves of bread, so we enter 3 in the Quantity text field as shown in image (b), then select the Save button from the navigation bar. We will be returned to the table view, which is shown in image (c). Note that the value 3 is displayed to the right of Bread, which tells us that the quantity of the bread sold to Candace was three.
We can again select the Add button to add additional products sold to the customer. The next given image (a) displays the view when Eggs is selected from the available products list. The next given image (b) shows how the name, price, and product image automatically appear, asking the user to fill in the quantity sold.
The quantity entered here will be deducted from the product inventory in the Master Products entity. After selecting the Save button, all products sold to the customer are displayed, as shown in the next image (c). The products will be displayed in sorted alphabetical order.
The Edit button shown in the preceding image (c) is used to delete a product entry sold to the customer. When the Edit button is tapped, we'll see a deletion icon to the left of the items as shown in the next image (a). Note that if we delete a customer, the list of products sold is automatically deleted as well.
Automatic Master Product Update
The quantity sold to a customer is automatically deducted from the master product's quantity in hand. To see if the stock has been updated, first click on the Master Product Information button from the toolbar at the bottom of the main view (the first view of the application); we'll see the list of products we saved earlier, as shown in the given image (b). After selecting a master product, we'll see the page that displays the master product information, as shown in next given image (c). And we'll find that the quantity of the master product has been adjusted accordingly.
- In this article, we had an introduction of what Core Data is and its features that make it a preferred framework used for persisting information.
- We also had a brief idea of the Data Model and how it is related to entities, properties, attributes, relationships, inverse relationships, and so on.
- We have also learned about the concept of MVC and the role of the terms: Managed Object Model, Managed Object, and Managed Object Context. Finally, we saw the Core Data API and Persistent Store, Persistent Store Coordinator, Fetch Request, and FetchedResultsController.
- Also, we took a detailed look at the different functions that can be performed by the application.
- We saw different screenshots the variety of application views, along with their respective controls. Also, we saw the tasks performed when different view controls are selected.
- Core Data iOS: Designing a Data Model and Building Data Objects [Article]
- Build iPhone, Android and iPad Applications using jQTouch [Article]
- Getting Started With Cocos2d [Article]
- Cocos2d for iPhone: Surfing Through Scenes [Article]
- Development of iPhone Applications [Article]
- Jailbreaking the iPad - in Ubuntu [Article]
- Cocos2d for iPhone: Adding Layers and Making a Simple Pause Screen [Article]
- Cocos2d for iPhone: Handling Accelerometer Input and Detecting Collisions [Article]