Architecture
Structure
Application (Model Objects)
↓
Managed Object Context (Managed Objects)
↓
Persistent Store Coordinator
↓
Persistent Object Store (Source Objects)
Note: Model objects within the application become Managed objects in Core Data framework.
Managed Object Model
- In core data, a schema is represented by a managed object model which is an instance of “NSManagedObjectModel” class.
- The model contains
- entities – that are instances of “NSEntityDescription” class.
- fetch request templates – that are instances of NSFetchRequest.
- An entity is a metadata (similar to Table DDL) that describes the columns and relations of corresponding objects (similar to Table rows). It contains
- attributes – that are instances of “NSAttributeDescription”.
- relationships – that are instances of “NSRelationshipDescription”.
- fetched properties – that are instances of “NSFetchedPropertyDescription”
- Most importantly, an entity contains its name and name of the class that represents the entity during runtime. Entities allow inheritance, abstracts etc.
- Many of the elements in a managed object model (entities, attributes, relationships) have an associated user info dictionary. We can put whatever information necessary into this, as key-value pairs. Usually we keep version details of entity, predicate for fetch property etc.
- Core data also allows “configurations”, which is a set of named entities. This is useful when storing different entities in different stores.
Managed Object
-
An instance of NSManagedObject, which is like a dictionary/generic container for properties described by its associated NSEntityDescription object.
-
Life cycle of managed object is handled by core data.
-
If a managed object is subclassed, we can override following methods.
init - Not advised
initWithEntity - Not advised (undo, redo can be affected)
awakeFromInsert - Called only once in the life-time, ie when the object is first created.
awakeFromFetch - Called every time the object is re-initialised, ie when fetched from store.
didTurnIntoFault - Invoked when object is turned into a Fault.
dealloc - Not advised
Managed Object Context
-
Managed Object Context is a scratch pad containing a collection of object graphs.
-
When objects are fetched from persistent store, temporary copies are brought into this scratch pad.
-
All managed objects must be registered with the Context.
-
Objects in a context can be modified as we wish.
-
Context tracks the changes, ensures relationships and validity.
-
However until we save (commit) the changes, the persistent store remains unaltered
Persistent Store Coordinator
-
It connects the managed object contexts and persistent stores.
-
It presents a group of persistent stores as a single aggregate store to the context.
-
A coordinator can only be associated with one managed object model.
Persistent Store
-
Stores the Source objects, in a single file or other external data store.
-
A given object in a persistent store may be edited in more than one object context simultaneously. But each context has its own managed object that corresponds to the same source object in the store. In such a case, while saving one needs to ensure consistency.
Fetch Request
-
Fetch requests are used to retrieve data using managed object context.
-
It has 3 parts, an entity name, a predicate and an array of sort descriptor objects
Using Managed Object Models
Compiling Data Model
-
Done by …/Developer/usr/bin/momc
-
Unversioned data model source (.xcdatamodel) gets compiled into a “.mom” file
-
Versioned data model source (.xcdatamodeld) gets compiled into a “.momd” file
Loading Data Models
-
initWithContentsOfURl – To load a single model
-
mergedModelFromBundles – To load multiple models in one shot, without specifying their names
Versioning the data models
-
A store can only be opened by the data model that created it.
-
Better to create versioned data models, in case old stores need to be opened
Localization of Model
-
Can be done by using a localizaton dictionary or Strings file
-
For Test.xcdatamodeld, the strings file will be Test.strings
"Entity/Emp" = "Employee";
"Property/firstName" = "First Name";
Creating, Initializing, Saving managed objects
Create & Initialize
-
A managed object must be an instance of NSManagedObject or its subclass.
-
It must exist inside its managed object context.
-
It has an associated entity description that describes the properties of the object.
-
Easiest method is
// Returns an instance of the class representing the entity
NSEntityDescription.insertNewObject(forEntityName:, into:)
-
Behind the scenes, NSEntityDescription.insertNewObject does the following.
let coordinator = context.persistentStoreCoordinator
let model: NSManagedObjectModel = coordinator.managedObjectModel
let myEntity: NSEntityDescription = model.entitiesByName[“MyEntity"]
/* Or
let myEntity: NSEntityDescription = NSEntityDescription.entity(forEntityName: “MyEntity”, in: context)
*/
let myObject: NSManagedObject = NSManagedObject(entity: myEntity, insertIntoManagedObjectContext: context)
-
If there is a class (a subclass of NSManagedObject) that represents MyEntity, we can do the following as well
let myObject: MyClass = MyClass(entity: myEntity, insertInto: context)
Fetch
-
By sending fetch request to managed object context
-
If an object is edited in 2 contexts, save by one will not be automatically fetched by the other. For that one has to use “refresh(_ object: NSManagedObject, mergeChanges flag: Bool)”
Save
-
Using context.save
-
Each managed object has an object ID that uniquely identifies it. (myObject.objectID)
-
On creation, it gets a temporary ID. (myObject.objectID.isTemporaryID)
-
On saving to store, it gets a permanent ID
Delete
-
context.delete(myObject)
-
Afterwards we need to save the context to make the changes in store
Undo and Redo
-
Each context has an undo manager that keeps track of changes to objects through key-value observing.
-
One can undo something by sending an “undo” request to context.
-
Similary a redo can be done by sending a “redo” request to context.
-
Operations can also be grouped to allow batch undo or redo.
-
Undo registration can be disabled as well (if a base set needs to be maintained, which will not be undone).
-
All changes since last save can be rolled back by sending “rollback” request to context.
-
Context can be reset to its base state by sending a “reset” request.
Fault
-
Fault is a placeholder object that represents a managed object that has not been fully initialized.
-
There is object fault as well as relationship fault.
-
When a “fault” object/relation is read, the target is automatically loaded from the store.
-
Fault helps to reduce memory footprint.
-
We can use “isFault” on an object to check, without actually firing the fault.
-
To save memory/break strong reference cycles, an object can be explicitly turned into Fault using “refresh(_ object: NSManagedObject, mergeChanges flag: Bool)”