Core Data
-
date_range Nov. 20, 2016 - Sunday infosortiOS Developmentlabelioscore dataiclouduimanageddocument
“It’s all about how core data works.”
Database
Some times you need to store large amount of data or query it in a sophisticated manner. And we want it to be object-oriented.
Core data framework is very powerful.
How does it work?
- Create a visual mapping between database and objects;
- Create and query for objects using object-oriented API;
- Access the “columns in the database table” using @propertys on those objects.
- Create a core data model, the visual map in xcode.
An Object Context
You need an NSManagedObjectContext
.
It is the hub around which all Core Data activity turns.
How do I get one?
There are two ways:
-
Create a
UIMangedDocument
and ask for itsmanagedObjectContext
(a@property
). -
Click the “Use Core Data” button when you create a project (only works with certain templates, then you AppDelegate will have a managedObjectContext @property).
There will be an
@property
and a methodsaveContext
generated for managing the core data.
@property (readonly, strong) NSPersistentContainer *persistentContainer;
// The persistent container for the application. This implementation creates and returns a container, having loaded the store for the application to it.
- (void)saveContext;
We’re going to focus on doing the first one UIManagedDocument
.
UIManagedDocument
UIManagedDocument
inherits from UIDocument which provides a lot of mechanism for the management of storage. It also good for iCloud support. Think of a UIManagedDocument
as simply a container for your Core Data database.
1. Create a UIManagedDocument
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *documentsDirectory = [[fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] firstObject];
NSString *documentName = @"MyDocument";
NSURL *url = [documentsDirectory URLByAppendingPathComponent:documentName];
UIManagedDocument *document = [[UIManagedDocument alloc] initWithFileURL:url];
This creates the UIManagedDocument instance, but does not open nor create the underlying file.
2. Open or Create a UIManagedDocument
Check if the UIManagedDocument
’s underlying file exists on disk:
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:[url path]];
Here is an example:
self.document = [[UIManagedDocument alloc] initWithFileURL:(URL *)url];
if ([[NSFileManager defaultManager] fileExistsAtPath:[url path]]) {
[document openWithCompletionHandler:^(BOOL success) {
if (success) [self documentIsReady];
if (!success) NSLog(@"couldn’t open document at %@", url);
}];
} else {
[document saveToURL:url forSaveOperation:UIDocumentSaveForCreating
completionHandler:^(BOOL success) {
if (success) [self documentIsReady];
if (!success) NSLog(@"couldn't create document at %@", url);
}];
}
- (void)documentIsReady {
if (self.document.documentState == UIDocumentStateNormal) {
// start using document
NSManagedObjectContext *context = self.document.managedObjectContext;
}
}
3. Saving & Closing
- Notice that
UIManagedDocument
s AUTOSAVE themselves! - Will automatically close if there are no strong pointers left to it.
NSNotification
How would you watch a document’s managedObjectContext?
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[center addObserver:self
selector:@selector(contextChanged:)
name:NSManagedObjectContextDidSaveNotification
object:document.managedObjectContext]; //don’t pass nil here!
}
- (void)viewWillDisappear:(BOOL)animated
{
[center removeObserver:self
name:NSManagedObjectContextDidSaveNotification
object:document.managedObjectContext];
[super viewWillDisappear:animated];
}
Core Data
Now we use the UIManagedDocument
’s managedObjectContext
@property
to insert/delete objects in the database and query for objects in the database.
Query
We can do this by executing an NSFetchRequest
in our NSManagedObjectContext
.
Four important things involved in creating an NSFetchRequest
Entity
to fetch (required);- How many objects to fetch at a time and/or maximum to fetch (optional, default: all);
NSSortDescriptor
to specify the order in which the array of fetched objects are returned;NSPredicate
* specifying which of those Entities of those Entities to fetch (optional, default is all of them).
Dependency Injection
Q: How to get managedObjectContext for viewController other than getting it from appDelegate?
A: Use Dependency Injection
Basically the caller/constructor should be setting the NSManagedObjectContext onto the called/constructed.
In your AppDelegat
e you should set the NSManagedObjectContext
into the rootViewController
that is associated with the UIWindow
.
Your rootViewController
should then set the NSManagedObjectContext
into the next view controller and so on.
How? It is just a simple proper on the view controller class and the caller uses:
[nextViewController setManagedObjectContext:[self managedObjectContext]];
Some others may recommend a singleton but that is another deep dark pit that is best avoided.
KF