views:

1421

answers:

4

Hi,

I'm writing a coredata based iPhone app that displays recipes. To improve performance, when displaying them in a TableView, I want to enable batching (-setFetchBatchSize:) and fetching only the "name" attribute (-setPropertiesToFetch:). When I turn on both, it doesn't work and the list is empty. As soon as I comment out one of the lines marked in the code below, it works fine.

What am I missing here? Is it impossible to have both?

NSFetchRequest *fetchRequest = [[[NSFetchRequest alloc] init] autorelease];
[fetchRequest setEntity:[NSEntityDescription entityForName:@"Rezept" inManagedObjectContext:chk_context]];
// *snip*

//BATCHING
[fetchRequest setFetchBatchSize:25];  

NSDictionary *entityProperties = [[NSEntityDescription entityForName:@"Rezept" inManagedObjectContext:chk_context] propertiesByName];

//PROPERTIES
[fetchRequest setPropertiesToFetch:[NSArray arrayWithObject:[entityProperties objectForKey:@"name"]]];
A: 

Update: When I NSLog the error after

[fetchedResultsController performFetch:&error];

I get "NSUnderlyingException = The database appears corrupt. (invalid primary key);". But I don't know what that means and what it has to do with enableing both methods.

A: 

Looks a lot like you found a bug in CoreData. You can verify for sure by turning on SQL logging - I'm guessing turning on both options generates slightly invalid SQL.

The option you want to use is "com.apple.CoreData.SQLDebug 1" - you can specify this from the command-line, or set the default on your program.

-Wil

Wil Shipley
The CoreData debug framework only works on the desktop, no? I didn't think there was an iPhone version of the debug frameworks.
Hunter
I'm not talking about debug frameworks. I'm saying, set an environment variable or a default to trigger extra logging in the normal CoreData framework.
Wil Shipley
Wil, have you actually gotten this to work on the phone? I haven't had any luck, and this person suggests it's a known bug: http://stackoverflow.com/questions/822906/how-do-i-get-the-coredata-debug-argument-to-output-to-the-console
Ross Boucher
No, haven't tried on iPhone.
Wil Shipley
A: 

Hunter you can use com.apple.CoreData.SQLDebug 1 on the phone but not using the simulator

Anthony Mittaz
You should not disguise comments as answers, bad style.
Till
A: 

I am far from a core data expert, but I got this to work successfully in my situation. I think the "conflict" between setFetchBatchSize and setPropertiesToFetch is more a side-effect of how core data works and not a bug per-se.

In my case, I did two fetches. In the first one, the result type was set to NSManagedObjectResultType and I used setFetchBatchSize to limit the amount of data actively brought into memory. In the second fetch, I populate an array of titles based on a single attribute and set the result type to NSDictionaryResultType and fetchBatchSize to 0 (infinite).

Based on testing, this scenario works perfectly. All the records in the initial fetch (with the actual managedObjects) are faulted and memory-limited by the fetchBatchSize. The second fetch returns a simple dictionary of titles. This takes much less memory than iterating through all the actual managedObjects to access the title attribute. It makes sense that the second fetch needs fetchBatchSize disabled as it returns the fully populated dictionary as a single result and batching wouldn't be appropriate.

I'm not sure I'm being 100% clear here (core data terminology is a bit arcane...) but the bottom line is that I think everything is working as intended.

thevoid