Core Data has selects


May 2, 2014

After my last post, there was an interesting side discussion on Twitter (with @macfanatic and @kastiglione) about some alternatives. It was interesting enough that I thought it would make good material for another post. So here ya go!

So, to revisit the last post Core Data in Motion - Chapter 2, we discussed the notion that Core Data doesn’t really have the notion of a “select” clause.

What is the impact of this limitation?

If you have a large monolithic model, but just wanted a subset of the attributes for your current view, like, say a MAP, you’d probably want to do something similar to the ActiveRecord query:

Well.select(:uwi, :well_name, :surface_latitude, :surface_longitude)

But you can’t do that in Core Data. When you execute a Core Data fetch, you get the option of getting back object ids only or whole objects only .

Or can you?

That was the point under discussion on Twitter. There is actually another option, but it comes with its own limitations. So let’s take a look at that other option, and see what it gives us, and what it takes away.

If you look at the SDK docs for NSFetchRequest, you will see a method called setPropertiesToFetch. The SDK description for this method is:

Specifies which properties should be returned by the fetch. The 
property descriptions may represent attributes, one-to-one
relationships, or expressions. The name of an attribute or
relationship description must match the name of a description 
on the fetch request’s entity.

Parameters:
    values (Array) — An array of NSPropertyDescription objects that 
    specify which properties should be returned by the fetch.

Returns:
    (Object)

Hey! So you can get your NSFetchRequest to return only this specified subset of properties! Isn’t that just like a select?

Well, not quite. You see, when you run the NSFetchRequest with the propertiesToFetch specified, it will still ignore your propertiesToFetch, unless you have also specified a resultType of NSDictionaryResultType. This is detailed in the answer to this Stack Overflow question.

Then, when you run the NSFetchRequest with some propertiesToFetch and a resultType of NSDictionaryResultType you get back an array of NSDictionary items, NOT your NSManagedObjects. So your results won’t have any of the methods you’ve declared on those NSManagedObjects, like, for instance, if you implemented the MKAnnotation interface so that you can drop those results on an MKMapView (which was my particular issue with this).

I will further note that the Stack Overflow post also indicates that the NSFetchedResultsController doesn’t play nicely with NSDictionaryResultsType, which would limit it’s usefulness with most standard UITableViewControllers implementations, too.

So… I can’t use these results on my map, and it won’t play nicely with my list view, either. I’m sure it’s useful in some use cases, but its limitations made it useless for both of mine, so this is where NSFetchRequest.propertiesToFetch and I parted company.