Core Data has a number of features and abilities that are not commonly used. Chief among those are fetched properties. In discussing them with a number of developers, most have never heard of them and those who have heard of them couldn’t come up with a viable use case for them.
To be honest, I don’t have a lot of use cases for them myself. They are definitely not one of the core features of Core Data that I recommend people learning when they are initially getting comfortable with the framework.
In this article we will discuss one use case for fetched properties and the impacts.
The Use Case
The use case for fetched properties that I have run across a few times comes into play when you have more than one persistent store file on disk. Imagine you are building a recipe application (one of my favorite examples). You decide to include a pre-built read-only database with existing recipes. However, your application has the ability to add notes and social comments to a recipe.
You want to keep the recipe database as read only (you have a separate one for new recipes) but you want the user to be able to add comments. Where do we put the data?
In this contrived situation, storing the comments (and other metadata) in another store makes sense. Unfortunately we can’t have relationships across physically separate stores.
Enter the Fetched Property.
A fetched property is a property added to a
NSManagedObject entity that instead of storing a value or a relationship, it stores a
NSFetchRequest. When the property is accessed for the first time the
NSFetchRequest is fired and the results are returned.
A fetched property always returns a
NSArray (well a subclass but that is a minor detail) and it can be configured to sort the results.
Unfortunately, the editor in Xcode does not permit adding sort criteria so the only way to add a sort to a fetched property is to create the fetched property in code. Hopefully that will be corrected in some future release of Xcode.
What does a fetched property look like? In the Core Data model editor, a fetched property is added just like an attribute or a relationship. Then in the Data Model inspector you can configure the
The Destination is the entity that will be returned by the fetched property. The predicate is a string representation of the
NSPredicate configured within the
Further, the predicate can use one of two variables to help configure it:
$FETCH_SOURCE gets replaced by a reference to the entity that owns the fetched property. By using this variable we can reference properties in the owning entity.
$FETCHED_PROPERTY gets replaced by a reference to the the property description of the fetched property. The property description includes key value pairs that are accessible from within the predicate. I have not run across a situation where I have used this variable.
The sharp edges
There are unfortunately some concerns with fetched properties.
Unlike a relationship, there is no way to pre-fetch a fetched property. Therefore, if you are going to fetch a large number of entities and then desire to access the fetched property for those properties, they are going to be fetched individually. This will drastically impact performance.
Fetched Properties are only fetched once per context without a reset. This means that if you add other objects that would qualify for the fetched property after the property has been fetched then they won’t be included if you call the fetched property again. To reset the fetched property requires a call to
A fetched property always returns an array. While this is not a major issue if in fact you want more than one object returned. However, when that is not the case it is an additional method call that you need to make every time or add a convenience method. More code equals more bugs.
To use or not to use
Fetched properties are not a main line piece of Core Data. It appears that even the Core Data team (or the Xcode team at least) agrees with that assessment based on how little effort is given to them in the model editor. Should you use them?
It depends. If you are joining two separate persistent stores and need a soft relationship between entities in those stores then yes, you can use them. They do work.
Be mindful of the edges, they are sharp.