Fetched properties are a feature of Core Data, similar in concept to computed properties on Swift objects. This post presents an overview of fetched properties in Core Data with an example, and provides an alternative implementation:
Core Data Fetched Properties
Fetched Properties in Core Data are properties that return an array value from a predicate. A fetched property predicate is a Core Data query that evaluates to an array of results. In this blog post, a fetched property called contractors
will be created on a Business
entity that will return an array of all People
in the Business
that are contractors.
Fetched Property Example
First, create a Core Data model with two entities: Person
and Business
. Person
has name
and type
String
attributes. Business
has a name
String
attribute. Business
also has a one-to-many relationship people
to Person
, the inverse is the job
relationship on Person
. Adding the Person
and Business
entities to a Core Data model should look like this:
Next, add a fetched property contractors
to Business
. This can be done by clicking the +
button under the Fetched Properties
section in Business
entity. Name the fetched property contractors
and enter the following query for the predicate:
type LIKE [c] "contractor" AND job == $FETCH_SOURCE
You may be wondering what LIKE [c]
and $FETCH_SOURCE
mean. This post presents an example of Fetched Properties for reference, but there are other implementations to consider that do not use complex query language. Please make sure to read the Alternative To Core Data Fetched Properties section below! If you determine fetched properties are the right approach for you, the Apple Core Data Documentation on Weak Relationships (Fetched Properties) goes into detail about predicate syntax specific to fetched properties.
Adding the contractors
fetched property on the Business
entity will look like:
Next, click on the contractors
Fetched Property and set the Destination to Person
in the Attributes Inspector. The Destination is the entity type a fetched property will query using the Predicate:
Now, the fetched property can be used in Swift:
// Get Core Data managed object context
let delegate = UIApplication.shared.delegate as! AppDelegate
let context = delegate.persistentContainer.viewContext
// Create People core data models
let steve = Person(context: context)
steve.name = "Steve"
steve.type = "contractor"
let tim = Person(context: context)
tim.name = "Tim"
tim.type = "employee"
let amelia = Person(context: context)
amelia.name = "Amelia"
amelia.type = "contractor"
// Create a Business core data model
let business = Business(context: context)
business.name = "Orange Computers"
business.addToPeople(tim)
business.addToPeople(steve)
business.addToPeople(amelia)
// Save context
try! context.save()
// Use fetched property
let contractors = business.value(forKey: "contractors")
as! [Person]
for person in contractors {
print(person.name)
}
// Expected output:
// Steve
// Amelia
Alternative To Core Data Fetched Properties
A Core Data fetched property has some drawbacks that developers should be aware of:
- Debugging fetched properties is more difficult than debugging Swift code, and in some cases no errors are logged even if a fetched property resulted in an error
- Fetched properties cannot take arguments the same way as Swift functions can
- Fetched properties are cached when evaluated, meaning fetched properties may not always return the expected value without refreshing the object.
Implementing a computed property in a Swift Core Data model extension is often a clear, more intuitive way to implement a fetched property. Here is an alternative example implementation that produces the same result as the fetched property example without the drawbacks:
// Extend the Business entity
extension Business {
// Create a contractors computed property
var contractors: [Person] {
// Use a predicate to filter the people relationship
let predicate = NSPredicate(
format: "type LIKE [c] %@", "contractor"
)
return Array(people!.filtered(using: predicate))
as! [Person]
}
}
Fetched Properties In Core Data
That’s it! In some cases core data fetched properties may provide a useful way to execute predicates, but there is often a better implementation without the drawbacks associated with fetched properties in Swift.