I have a table view that is managed by an NSFetchedResultsController. I am having an issue with a find-or-create operation, however. When the user hits the bottom of my table view, I am querying my server for another batch of content. If it doesn’t exist in the local cache, we create it and store it. If it does exist, however, I want to append that data to the fetched results controller and display it. I can’t quite figure that part out.
Here’s what I’m doing thus far:
- The NSFetchedRequestController when initialized queries for the latest 100 results from the database (using
setFetchLimit:). Even if there are 1000 rows, I only want 100 accessible at first. - Passing the returned array of values from my server to an NSOperation to process.
- In the operation, create a new managed object context to work with.
- In the operation, I iterate through the array and execute a fetch request to see if the object exists (based on its server id).
- If the object doesn’t exist, we create it and insert it into the operations’ managed object context.
- After the iteration completes, we save the managed object context, which triggers a merge notification on my main thread.
During the merge, the newly created objects from step 4 are inserted into the table, but any object that already existed and was just fetched does not. Here’s the relevant code from my NSOperation
for (NSDictionary *resultsDict in self.results)
{
NSNumber *dbID = [NSNumber numberWithLong:[[resultsDict valueForKey:@"id"] longValue]];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[NSEntityDescription entityForName:kResultEntityName inManagedObjectContext:moc]];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat: @"(dbID == %@)", dbID]];
NSError *error = nil;
NSManagedObject *newObject = nil;
// Query the data store to see if the object exists
newObject = [[moc executeFetchRequest:fetchRequest error:&error] lastObject];
[fetchRequest release];
// If it doesn't exist, create it.
if ((tweet == nil))
{
// Create the NSManagedObject and insert it into the MOC.
}
}
What I want to pass to my main thread is the newly created objects plus any existing objects that may have been fetched in the fetch request each time the loop iterates.
I feel like it’s something simple I’m missing, and could use a nudge in the right direction.
Can you explain this a little? I am not sure what you mean by the ones that previously existed. Is it objects that didn’t match the filter on your table that now do after the retrieval or are you saying that the previous objects disappear from the table?
Also, how are you implementing the delegate methods for the
NSFetchedResultsController? Are you doing a simple table reload or are you inserting/moving rows?Update
There are a couple of ways to do this but they would require some experimentation on your part. I would first play with the idea of “touching” the objects that were fetched. Perhaps updating a ‘lastAccessed’ date or something so that these objects will come across the merge as “updated”. I suspect that is the easiest path.
Baring that, another option would be to broadcast a notification of those objects back to the main thread (using their
NSManagedObjectIDas the carrier across the thread boundaries) so that you can manually update them; however that is less than ideal.