views:

130

answers:

3

Is it wrong to use an NSFetchedResultsController purely for data management, i.e., without using it to feed a UITableView?

I have a to-many relationship in a Core Data iPhone app. Whenever data in that relationship changes, I need to perform a calculation which requires that data to be sorted. In Apple's standard Department/Employees example, this would be like determining the median salary in a given Department. Whenever an Employee is added to or removed from that Department, or an Employee's salary changes, the median calculation would need to be performed again.

Keeping data sorted and current and getting notifications when it changes sounds like a great job for NSFetchedResultsController. The only "problem" is that I'm not using a UITableView. In other words, I'm not displaying sorted Employees in a UITableView. I just want an up-to-date sorted array of Employees so I can analyze them behind the scenes. (And, of course, I don't want to write a bunch of code that duplicates much of NSFetchedResultsController.)

Is it a bad idea to use an NSFetchedResultsController purely for data management, i.e., without using it to feed a UITableView? I haven't seen this done anywhere, and thought I might be missing something.

A: 

There's nothing wrong with using NSFetchedResultsController without a view. Your use case sounds like a good reason to not re-invent the wheel.

Barry Wark
A: 

To me, this sounds like an appropriate use of NSFetchedResultController. it might be a bit overkill, as its primary use IS to help populate and keep up to date tableViews, but if you are willing to put up with the added complexity, there is no reason to not use it as such. Correct use of notifications would be the other method and it is just as complex i would estimate.

Jesse Naugher
+3  A: 

I would not call it bad but definitely "heavy".

It would be less memory and CPU to watch for saves via the NSManagedObjectContextDidSaveNotification and do the calculation there. The notification will come with three NSArray instances in its userInfo and you can then use a simple NSPredicate against those arrays to see if any employee that you care about has changed and respond.

This is part of what the NSFetchedResultsController does under the covers. However you would be avoiding the other portions of the NSFetchedResultsController that you don't care about or need.

Heavy

NSFetchedResultsController does more processing than just watch for saved objects. It handles deltas, makes calls to its delegates, etc. I am not saying it is bad in any way shape or form. What I am saying is that if you only care about when objects have changed in your relationship, you can do it pretty easily by just watching for the notifications.

Memory

In addition, there is no reason to retain anything since you are already holding onto the "Department" entity and therefore access its relationships. Holding onto the child objects "just in case" is a waste of memory. Let Core Data manage the memory, that is part of the reason for using it.

Marcus S. Zarra
Thanks for the fast answer and suggestion! If using NSFetchedResultsController isn't bad, then this sounds like a performance issue. In some instances, it would be useful for me to keep the sorted data around for other user-initiated calculations that require it. I'm assuming that fetchedObjects is where most of the memory burden comes from. If so, I'll lose the memory savings by retaining the sorted data as part of handling the save notification. But what is the extra CPU usage you're referring to? Is that from using a fetch in NSFetchedResultsController instead of a relationship accessor?
James Huddleston
You use fetches to find objects based on attributes. To find relationships, you walk the object graph by calling following the relationships of fetched objects. Walking the graph is more efficient because the context only needs faults (i.e. objects with no attribute data loaded) to follow relationships.
TechZen
The only reason I would hold onto the sorted "Employee" objects is to avoid resorting them as part of each user-initiated calculation.
James Huddleston
Personally in that case I would create a convenience method that returns the employees sorted instead of retaining them but that is arguably a personal preference.
Marcus S. Zarra
I like that approach; that's what I'm currently doing. :) Well, actually I filter the "employees" first and sort the results. The filtered data set can be relatively small. So I thought: "Might it be smarter to filter/sort the large data set once and cache the small array of results rather than repeatedly filter the large data set every time I need the sorted subset? I could create a class to manage the filtered/sorted data and use change notifications from the MOC to keep everything up-to-date. Hmm... Isn't there a class that essentially does that?" And thus my question was born.
James Huddleston