Swift Package Manager smoothly integrates with the workflow in Xcode 11, but comes with one small limitation: we can not bundle resources with Swift packages. For Core Data this means that we can not include model files.
The solution is to create Core Data model programmatically. Let’s see how we can do this and the process can be improved.
TL;DR; I encountered this problem when I decided to create the index of downloaded images for my URLImage package. I came up with declarative approach and created a separate Swift package: CoreDataModelDescription to describe the model in code.
Core Data model in code
Core Data provides classes to describe the model in code, here are some:
NSEntityDescriptiondescribes an entity in a model: name, list of properties, and
NSPropertyDescriptiondescribes a property of an entity: name, is it transient, is it optional. Property is a base for attributes and relationships.
NSAttributeDescriptionallows to specify a type, default value, and other features of an attribute in an entity.
NSRelationshipDescriptiondescribes relationships between two entities.
Both attribute and relationship are properties of an entity. There are more descriptions for sophisticated models. Consider this as minimum required to create feasible Core Data model.
Let’s take a simple model like this:
Model file (
.xcdatamodeld) is a package and model is actually described in XML:
We can follow it to describe the model in code. This routine by steps:
NSEntityDescriptionobjects and establish sub-super entity connections between them.
NSAttributeDescriptionfor the fields that store data in your model.
NSRelationshipDescriptions. Establish inverse relationships.
- Fill properties on the entities with attributes and relationships.
NSManagedModel can be created like this:
For the reference this is how
NSManagedObject subclasses look like:
As you can see the process is not hard but describing a model takes a lot of code. This is a good example of declarative (XML) vs imperative approaches.
Describing Core Data model in code
It’s a shame not to try declarative approach in code to solve the problem. Here is what I came up with:
I really like how Swift Package Manager uses
Package.swift file to describe a package so I decided to follow its format.
Describing Core Data mode declaratively feels natural and allows to focus on the model itself.
CoreDataModelDescription is available as a Swift package. Give it a try.