2
votes

I have a Core Data SQLite type store, one of the attributes in my entity called Article is a string attribute called markAsArchived.

What I would like to do is setup a fetch request to get the first 100 items whose markAsArchived is not YES (string value, not bool).

So, here's the code I use to setup the fetch request, which returns 0 results.

NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Article"];
fetchRequest.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"date" ascending:NO]];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"markAsArchived != 'YES'"]];
[fetchRequest setFetchLimit:100];
NSError *error = nil;
self.articles = [NSMutableArray arrayWithArray:[self.managedObjectContext executeFetchRequest:fetchRequest error:&error]];

if (error) {
    //Handle the error
    NSLog(@"%@", error);
}

However, if I take that exact same predicate, remove it from the fetch request, but instead use it to filter the array returned by the fetch request, I get some what desired results. Here is the code I use to do this.

NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Article"];
fetchRequest.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"date" ascending:NO]];
[fetchRequest setFetchLimit:100];
NSError *error = nil;
self.articles = [NSMutableArray arrayWithArray:[self.managedObjectContext executeFetchRequest:fetchRequest error:&error]];

if (error) {
    //Handle the error
    NSLog(@"%@", error);
}
self.articles = [NSMutableArray arrayWithArray:[self.articles filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"markAsArchived != 'YES'"]]];

Now, my problem is that since I'm filtering the array of a 100 fetched items, the resulting filtered array usually ends up being less than 100 which is not what I want.

My guess is I'm doing something incredibly noobish when setting up the fetch request with the predicate. Any pointers as to what I might be doing wrong?

PS: Changing markAsArchived to a bool attribute instead of a string attribute is not an option.

Update: I have looked through the following questions, none of which seemed to have helped me.

NSPredicate Returns No Results with Fetch Request, Works with Array Filtering

Predicate works for array but not for fetchRequest

Update (March 1, 2013):* As far as I can tell, the executeFetchRequest returns an empty array, not nil. I double checked to be sure.

Here is the debug output I get with the launch argument...

2013-03-01 20:29:48.218 PROJECTNAME[753:907] CoreData: sql: SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZCONTENT, t0.ZDATE, t0.ZENCLOSURELENGHT, t0.ZENCLOSURETYPE, t0.ZENCLOSUREURL, t0.ZFULLTEXT, t0.ZIDENTIFIER, t0.ZIMAGE, t0.ZLINK, t0.ZMARKASARCHIVED, t0.ZREAD, t0.ZREADPOSITION, t0.ZSUMMARY, t0.ZTITLE, t0.ZUPDATED, t0.ZFEED FROM ZARTICLE t0 WHERE  t0.ZMARKASARCHIVED <> ? ORDER BY t0.ZDATE DESC LIMIT 119
2013-03-01 20:29:48.221 PROJECTNAME[753:907] CoreData: details: SQLite bind[0] = "YES"
2013-03-01 20:29:48.287 PROJECTNAME[753:907] CoreData: annotation: sql connection fetch time: 0.0689s
2013-03-01 20:29:48.289 PROJECTNAME[753:907] CoreData: annotation: fetch using NSSQLiteStatement <0x1f218d70> on entity 'Article' with sql text 'SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZCONTENT, t0.ZDATE, t0.ZENCLOSURELENGHT, t0.ZENCLOSURETYPE, t0.ZENCLOSUREURL, t0.ZFULLTEXT, t0.ZIDENTIFIER, t0.ZIMAGE, t0.ZLINK, t0.ZMARKASARCHIVED, t0.ZREAD, t0.ZREADPOSITION, t0.ZSUMMARY, t0.ZTITLE, t0.ZUPDATED, t0.ZFEED FROM ZARTICLE t0 WHERE  t0.ZMARKASARCHIVED <> ? ORDER BY t0.ZDATE DESC LIMIT 119' returned 0 rows with values: ( )
2013-03-01 20:29:48.291 PROJECTNAME[753:907] CoreData: annotation: total fetch execution time: 0.0734s for 0 rows.
2
I assume you have done the obvious: double-checked all property names (upper/lowercase) and re-generated the NSManagedObject subclasses? - Martin R
@MartinR : Affirmative. In fact, that's all I've been doing over and over again for days now. :-( - Sam J.
Can you check the return value of [self.managedObjectContext executeFetchRequest:fetchRequest error:&error] ? Does executeFetchRequest return an empty array or nil? (arrayWithArray would return an empty array in both cases, so you have to check the actual return value!) - Martin R
Another suggestion: Set the launch argument -com.apple.CoreData.SQLDebug = 3 and show us the debug output that is created for the executeFetch call. - Martin R
Did you make any progress with this strange problem? - Martin R

2 Answers

0
votes

Assuming you need the attribute markedAsArchived to be a string (which you will agree is bad design), the correct predicate for the fetch request is:

[NSPredicate predicateWithFormat:@"markedAsArchived != %@", @"YES"]

It is not safe to substitute constants as literals in the predicate format string. The above is the standard way to check for this attribute.

0
votes

I stumbled on the same issue ... in my case it was related to building the predicate string. You need to be careful if you use quotes or not. In your code I see:

[NSPredicate predicateWithFormat:@"markAsArchived != 'YES'"];

but it may actually need to be:

[NSPredicate predicateWithFormat:@"markAsArchived != YES"];

I had the same issue is NSNumber being wrapped in quotes.

Harry