Top 10 Core Data Tools and Libraries
We’ve compiled a list of the top 10 core data tools and libraries, making it even easier to work with Core Data. By Matthew Morey.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Top 10 Core Data Tools and Libraries
30 mins
3. MDMCoreData
MDMCoreData (disclaimer – this library is written by me!) is a collection of open source classes that make working with Core Data easier. It doesn’t try to hide or abstract Core Data, but instead enforces best practices and reduces the amount of boilerplate code required. It’s a better alternative than the Xcode Core Data Template.
MDMCoreData consists of the following four classes:
- MDMPersistenceController – A handy controller that sets up an efficient Core Data stack with support for creating multiple child-managed object contexts. It has a built-in private managed object context that saves asynchronously to a SQLite store.
- MDMFetchedResultsTableDataSource – Implements the fetched results controller delegate and a table data source.
- MDMFetchedResultsCollectionDataSource – Implements the fetched results controller delegate and a collection data source.
- NSManagedObject+MDMCoreDataAdditions – A category on managed objects providing helper methods for eliminating boilerplate code such as entity names.
One great feature of MDMCoreData is that it comes with a Core Data backed table data source — so you don’t have to worry about implementing one yourself.
Instead of implementing all the required methods in the UITableViewDataSource
and NSFetchedResultsControllerDelegate
protocol, you can just set your table’s data source to an instance of MDMFetchedResultsTableDataSource
. When instantiating the MDMFetchedResultsTableDataSource
object you simply pass in the table view and a fetched results controller:
- (void)viewDidLoad {
[super viewDidLoad];
self.tableDataSource = [[MDMFetchedResultsTableDataSource alloc] initWithTableView:self.tableView
fetchedResultsController:[self fetchedResultsController]];
self.tableDataSource.delegate = self;
self.tableDataSource.reuseIdentifier = @"WeatherForecastCell";
self.tableView.dataSource = self.tableDataSource;
}
A MDMFetchedResultsTableDataSource
does have a delegate, with two methods that must be implemented. One method configures the cell for your table:
- (void)dataSource:(MDMFetchedResultsTableDataSource *)dataSource
configureCell:(id)cell
withObject:(id)object {
OWMForecast *forecast = object;
UITableViewCell *tableCell = (UITableViewCell *)cell;
tableCell.textLabel.text = forecast.summary;
tableCell.detailTextLabel.text = forecast.date;
}
The second method handles deletions:
- (void)dataSource:(MDMFetchedResultsTableDataSource *)dataSource
deleteObject:(id)object
atIndexPath:(NSIndexPath *)indexPath {
[self.persistenceController.managedObjectContext deleteObject:object];
}
It’s far easier to implement the two required methods of MDMFetchedResultsTableDataSource
than to implement all of the methods required by the table data source and fetch results controller protocols.
You can find out more about MDMCoreData at the MDMCoreData Github repository.
2. Mogenerator
Since Core Data comes with full support for key-value coding (KVC) and key-value observing (KVO), there is no requirement to implement custom NSManagedObject
classes. You can get by using setValue:forKey:
and valueForKey:
when reading or writing attributes on your entities. But this tends to be cumbersome and hard to debug since strings can’t be checked at compile time for correctness.
For example, if you had a person
Core Data entity, you could read and write attributes like this:
NSString *personName = [person valueForKey:@"firstName"];
[person setValue:@"Ned" forKey:@"firstName"];
The person
object above is an instance of NSManagedObject
with an attribute named firstName
. To read firstName
, you use valueForKey:
with the key firstName
. Similarly, to set the first name of a person
object you can use setValue:forKey:
.
A better approach is to use standard accessor methods or dot syntax; however, to do this you must implement a custom subclass of NSManagedObject
for your entities. This lets you add model logic such as fetch requests and validation.
You have probably used Xcode’s Create NSManagedObjectSubclass functionality to quickly create a subclass for a single entity. Although it’s a nice shortcut, it can create extra overhead if you have a large model and can cause you grief when your model changes.
Re-creating the subclass means wiping out all of your custom model logic — which means you should host that logic outside of your custom model. This lends itself to a common pattern of creating custom subclasses with managed object properties along with categories for custom model logic.
The command line tool Mogenerator automates these exact tasks for you. It generates two classes per Core Data entity. The first class is for machine consumption and is continuously overwritten as the model changes. The second class is for all your custom logic and is never overwritten.
Mogenerator has a list of other benefits which include the following:
- No need to use
NSNumber
objects when reading or writing numeric attributes. - Helper methods for working with sets.
- Helper methods for creating new entities
- A method for entity identification.
Mogenerator can be installed from the DMG available on the Mogenerator website, or alternatively through Homebrew. To install Mogenerator using Homebrew, open Terminal and run the following command:
brew install mogenerator
Once installed, use the cd
command to change to your app’s directory, then run Mogenerator from Terminal like so:
$ mogenerator -m MySampleApp/ExampleModel.xcdatamodeld -O MySampleApp/Model --template-var arc=true
In the command above, you call Mogenerator followed by the location of your model with the -m
option. You can also specify where the generated classes should be located with the -O
option. When working with ARC you should also pass the --template-var arc=true
option.
You can make Xcode run Mogenerator for you by creating a Run Script Build Phase. Build Phases are descriptions of tasks that need to be performed by Xcode during a build.
To add a Build Phase, first select the target, select the Build Phases tab, then select Editor / Add Build Phase / Add Run Script Build Phase from the menu.
Add the following code in the Shell script text area under the new Run Script, making sure to modify the parameters to mogenerator
as suits your project:
if [ "${CONFIGURATION}" == "Debug" ]; then
echo "Running Mogenerator"
mogenerator -m MySampleApp/ExampleModel.xcdatamodeld -O MySampleApp/Model --template-var arc=true
echo "Finished Mogenerator"
else
echo "Skipping Mogenerator"
fi
The above run script will cause Xcode to run Mogenerator every time you run a debug build command. If there are no changes to the model, Mogenerator will do nothing and exit.
Now that you have incorporated Mogenerator into your workflow for quick subclass generation, you should take advantage of its other features.
For example, instead of unwrapping primitive values every time you can just add the suffix Value
on to them as illustrated by the following code snippet:
// Without Mogenerator
if ([person.isFriend boolValue]) {
// Do some work
}
// With Mogenerator
if (person.isFriendValue) {
// Do some work
}
Since bool types are stored as NSNumber
in Core Data, you must call boolValue
on the person
object before checking if the value is true. With Mogenerator, that extra step is no longer required as you can simply call isFriendValue
.
If Mogenerator looks like a useful addition to your toolbox, you can find more information on Mogenerator at its Github repository.