The Magic
So, how does all this work? How does the application run without creating any code at all? A great deal of this application hangs on Cocoa Bindings, Key-Value Coding, and Key-Value Observing. In my previous article I discussed Key-Value Coding and Key-Value Observing. Core Data builds upon the KVC/KVO framework and all the attributes of my Person object are accessible using valueForKey: against the Person object itself.
Each Person object is really an instance of NSManagedObject, and the NSManagedObjectContext is responsible for them. By defining the NSArrayController to retrieve all the Person objects from the managedObjectContext referenced in the application delegate, what really happens is that the NSArrayController executes a fetch against the context requesting all the Person objects. The context returns an NSArray of NSManagedObjects that are populated with the data from the Person records. As each record is altered, the KVO framework notifies the context that the data has changed. Similarly, when the NSArrayController is told to add a record, it requests that the context create a new NSManagedObject, which is then added to the array. The table and the fields then simply feed off of the data referenced in the NSArrayController.
Behind the scenes, the NSManagedObjectContext keeps track of what data has been added and/or modified. When a save is issued against the context, it then writes all the data out to the persistent store. Currently, there are three types of persistent stores available to Core Data: XML, binary, and SQLite. The default context for a new XCode project is a single XML store. This XML store is saved in the User's Library under Application Support. If the application needs to be able to access more than one store, it is possible to change this by changing the code generated as part of the Core Data application template. By altering the code that handles the context, it is possible to have an application that processes persistent stores just like a traditional data file.
The application delegate also has overridden the applicationShouldTerminate: method so that the context is saved to the store prior to the application terminating. This completely eliminates the need to manage loading and saving of the user's data, and in fact removes the need to bother the user with these details at all. Using this approach, it would be very easy to duplicate the functionality of Address Book.app or iCal.app and produce an application with a single persistent data store. However, if the application requires it, it is possible to manually control saving the store.