Core Data is Apple’s object-relational mapping framework for the Cocoa API, the programming interface used in developing applications for Mac OS X and the iOS mobile operating system. Core Data isolates the developer from any underlying SQL code, while still managing the entire object lifecycle. It persists object graphs by serializing them into binary, XML (on the desktop), or even a SQLite database.
The data persistence framework also includes a convenient ER diagramming tool accessible within Xcode, the IDE used for almost all Mac and iOS development. Like any good ORM framework, Core Data frees the developer from spending valuable project time on the plumbing around databases, allowing more focus on the business and domain logic necessary to solve their customer’s problem.
Designing a Data Model with Xcode
Most iOS projects implementing the Core Data framework start with a data model design using Xcode’s ER diagramming feature. Like most ER tools, the developer diagrams the entities, their attributes and data types, as well as the relationships between those entities. The Xcode ER tool does not have all the bells and whistles of a stand alone application like ERwin, but it works well for something embedded within a fully functional IDE.
Xcode ends up compiling the data model from this diagram into a structure used by the compiled version of the app or program. Apple recommends that data models also explicitly define an inverse relationship between entities. This helps Core Data enforce data integrity rules. Xcode creates managed data objects for each defined entity in the ER diagram. The developer interacts with these objects throughout the rest of the application to add business logic and other functionality.
Binding Data Objects Using Core Data
Interface Builder is the Xcode tool used to define a user interface for an iOS or Mac app. When used in conjunction with Core Data, Interface Builder facilitates setting up the controller logic to manage the data for any entity created in the data model.
“NSArrayController” objects can be used to link to the data object for each entity in the application’s data model. The developer simply sets the mode of each object to “Entity” and then selects the relevant entity name from the model. “NSArrayController”objects are useful for displaying data collections on-screen in an app.
A “TableViewController” – essentially a displayed item list in an iOS app – can now be bound to any table in the app’s data model using this array controller, while displaying the data from any of that table’s columns. The developer sets the controller key for the table view to “arrangedObjects,” while its model key path is set to the column name to be displayed.
Display controls – such as text fields, combo boxes, and text areas – are bound to individual table columns in the data model using a similar technique. Additional control properties are available to manage a field’s read only status, a combo box’s separate display and value fields, or a host of other options.
Data choreography controls, including the buttons used to manage adding, updating, and deleting records for a bound table, are also tied directly to the array controller for that table. Simply connecting a specific button to an action on the array controller [add, delete] is the only thing needed to set up that functionality.
Two main APIs control the underlying logic used in data binding with Core Data. The Key Value Coding (KVC) API is used primarily to access the attributes for a managed data table. Mimicking reflection, KVC allows the developer to iterate through all the fields for a table, without specifically knowing the individual field’s name. This reflective logic also works in the other direction, allowing the developer to set the value for each field on the table without implicitly knowing the field’s name. KVC helps the developer facilitate object-oriented programming techniques, like modularity or loose-coupling.
Key Value Observing (KVO) follows the observer pattern used in object-oriented programming. It allows the developer to track any data changes on a managed object. This becomes useful when implementing validation or “is dirty” logic.
Other Cocoa interface controls, including the “NSTreeController” and “NSSearchField,” also leverage the Cocoa Bindings (KVC/KVO) functionality from Core Data, allowing those controls to function with the minimum amount of code.
How Core Data Manages Migrations and Versioning
Core Data includes functionality to handle model versioning and data migrations. To implement versioning, the developer simply tells Xcode they want to create a new model version when selecting the data model in the project explorer. Any subsequent model changes are then saved to a new file. But simply running the application at this point triggers an error because the persistent data store does not match the new model. Thankfully, Core Data provides an automatic data migration feature.
Using the verbosely named “NSMigratePersistentStoresAutomaticallyOption” flag when initializing Core Data’s persistent store in code, causes the app to attempt a data migration if it detects a model versioning conflict.
Core Data migrations depend on mapping models to perform their magic. When creating a mapping model, Xcode first asks for the source and destination data models for the migration. The IDE then creates an initial set of mappings based on the model changes; these generated mappings are normally sufficient for most migration scenarios. Filter predicates are used to handle more complex mapping situations; essentially becoming a [WHERE] clause for the migration process. This allows only records containing specific data to be migrated, if necessary.
With Core Data’s automatic migrations and the appropriate mapping model, an iOS developer insures his customers remain isolated from any hassles related to changing a live application’s data model on the fly.
Mobile Considerations when Using Core Data
The differences between the Cocoa API for Mac OSX and iOS are generally minor; this close similarity also applies to Core Data on both platforms. Remaining conscious of the resource-constrained environment on the iPhone and iPad tends to be the most important consideration when developing a Core Data app for iOS.
Xcode also provides an easy path for developers who want to convert an existing iOS project to use Core Data’s persistence engine. Usually, creating a data model and adding some bootstrap code to initialize a managed object instance of that model are the only necessary steps in retrofitting Core Data to an iOS app. Each iOS app uses its own “sandbox” for file storage; the Core Data persistent store – no matter the format – is saved within this sandbox. SQLite tends to be the primary format for Core Data storage on iOS, probably due to its efficiencies in memory usage. XML is only available for the Mac OSX instance of Core Data.
Given the memory constraints of iOS compared to the Mac, Apple added a class, “NSFetchedResultsController,” which handles Core Data’s memory management of large result sets in an efficient manner. This is especially useful when displaying successive pages of data using a “TableViewController.”
A less robust Key Value Observer API is another difference between the desktop and mobile versions of Core Data. This forces the developer to code logic to update off-screen controls when the underlying data changes. Creating a delegate to handle data change notifications tends to be a common method to handle this issue.
There is little doubt Apple’s Core Data is a robust ORM framework that belongs in the skill set of any developer programming in the iOS and Mac OSX platforms. It provides a quality ER diagramming tool, in addition to a host of programming hooks to handle data persistence in an efficient manner.