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.

Leave a rating/review
Save for later
Share
You are currently viewing page 3 of 4 of this article. Click here to view the first page.

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.