Issue with fetching core data objects using NSPredicate - iphone

Before I start let me give you how my data model looks like:
I then have a fetch request with the following predicate:
NSArray *allowedPackNames = #[#"success, happiness, free"];
self.fetchedResultsController = [Author MR_fetchAllGroupedBy:nil
withPredicate:[NSPredicate predicateWithFormat:#"ANY quotes.quote.pack.packName IN %#", allowedPackNames]
sortedBy:AuthorKeys.name
ascending:YES
delegate:self];
I wanted to fetch all Authors that has a Quote with packName of success or happiness or free.
Author has a NSSet of quotes as you can see in the relationship table below. However when I execute this I get the following error:
CoreData: error: (1) I/O error for database at /Users/Abdul/Library/Application Support/iPhone Simulator/6.1/Applications/DA17421B-A54D-42E3-9694-FDCBFF7F8BA4/Library/Application Support/MyCoolApp/MyCoolApp.sqlite. SQLite error code:1, 'no such column: t2.ZQUOTE'
2013-04-05 15:26:47.175 MyCoolApp[78622:c07] Core Data: annotation: -executeRequest: encountered exception = I/O error for database at /Users/Aditya/Library/Application Support/iPhone Simulator/6.1/Applications/DA17421B-A54D-42E3-9694-FDCBFF7F8BA4/Library/Application Support/MyCoolApp/MyCoolApp.sqlite. SQLite error code:1, 'no such column: t2.ZQUOTE' with userInfo = {
NSFilePath = "/Users/Abdul/Library/Application Support/iPhone Simulator/6.1/Applications/DA17421B-A54D-42E3-9694-FDCBFF7F8BA4/Library/Application Support/MyCoolApp/MyCoolApp.sqlite";
NSSQLiteErrorDomain = 1;
}
Any idea why?

If I see it correctly, the predicate should be
[NSPredicate predicateWithFormat:#"ANY quotes.pack.packName IN %#", allowedPackNames]
i.e. you have to remove "quote", which is an attribute of the Quote entity, not a relationship.

Related

U_ILLEGAL_ARGUMENT_ERROR crashing my application

This is the error I am reciving when I select a value from my UITableView
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Can't do regex matching, reason: Can't open pattern U_ILLEGAL_ARGUMENT_ERROR (string Motron, pattern
libc++abi.dylib: terminate called throwing an exception
(lldb)
This is the first time I have had an error like this.. I am receiving it in my tableview method didSelectRowAtIndexPath on the second line of code shown below
// This predicate restricts the filterDataArray to the related values of the selected index
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%K like %#",#"MASTER",cell.textLabel.text];
filterDataArray = [dataArrayOfDictionaries filteredArrayUsingPredicate:predicate];
I have logged out the array of dictionaries and this is what one of the dictionary values looks like.
{
HASM = 1;
ISM = 0;
ISV = 0;
MASTER = Merc;
MANURE = 96;
}
There are about 60 or 17 of these dictionaries in the array.
any help would be greatly appreciated.
I think you are not correctly using predicate in this case, try this
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"MASTER CONTAINS [c]%#", cell.textLabel.text];
filterDataArray = [dataArrayOfDictionaries filteredArrayUsingPredicate:predicate];

Core Data NSSet returning empty array of objects

UPDATE: I had ghost entries in my database of games without players from before I implemented Players at all. It was returning those entries not the latest entries with the updated Model
I am working to get a Core Data database working and having some trouble with relationships. I'm very new to the whole thing so don't put anything past me I may no even understand the basics. But here we go anyway.
This is where I create a new Game Entity. The Players is a to-may relationship to Several Player entities that were selected and stored in an array.
Game *newGame = [NSEntityDescription insertNewObjectForEntityForName:#"Game" inManagedObjectContext:[SDDataManager dataManager].managedObjectContext];
[newGame setGameType:#"multipleChoice"];
[newGame setDate:[NSDate date]];
NSSet *playersSet = [NSSet setWithArray:players];
[newGame setPlayers:playersSet];
[newGame setCards:[NSKeyedArchiver archivedDataWithRootObject:selectedCards]];
NSError *error;
[[SDDataManager dataManager].managedObjectContext save:&error];
NSLog(#"New Game Error: %#",[error localizedDescription]);
The problem is that when I call it out of the database like this:
NSFetchRequest *requestSavedGame = [NSFetchRequest fetchRequestWithEntityName:#"Game"];
[requestSavedGame setFetchLimit:1];
NSError *error;
NSArray *loadedGame = [[SDDataManager dataManager].managedObjectContext executeFetchRequest:requestSavedGame error:&error];
NSLog(#"Load Game Error: %#",[error localizedDescription]);
Game *game = [loadedGame objectAtIndex:0];
NSLog(#"Players Set: %#",game.players);
NSLog(#"Players: %#",[game.players allObjects]);
The Players: is empty?? It returns this exactly:
Players Set: Relationship 'players' fault on managed object (0xd023b70) <Game: 0xd023b70> (entity: Game; id: 0xd023180 <x-coredata://E6A82377-31D2-4D11-B890-B3FDC5A03E0E/Game/p1> ; data: {
cards = <62706c69 73743030 d4010203 0405086e 6f542474 6f705824 6f626a65 63747358 24766572 73696f6e 59246172 63686976 6572>;
currentPlayer = 0;
date = "2012-03-27 18:20:07 +0000";
gameType = multipleChoice;
players = "<relationship fault: 0xd01fd60 'players'>";
})
Players: ( )
I have no understanding why the players is a full array, then a full set when it goes in but when it comes out the [set allobjects] returns an empty array...
I would suggest you to use valueForKey for whatever key.
In core data fault is not an error, it means you are trying to access from core data which does not exist. and i would say you should use setPropertiesToFetch which specifies which properties should be returned by the fetch.
The message saying that it is a fault does not mean that it is empty. It simply means that the data has not been loaded from the database. If you access it like normal, you should see your data there. Try this and see what it says:
NSLog(#"Players count: %i", [game.players count]);
Read about faults here: Core Data Programming Guide - Faulting and Uniquing

Searching for an id in Core Data

I am getting some unexpected behavior with CoreData and NSPredicate. In a large database population I have different Managed Objects relating to one-another. However, I have a problem with the following. When giving an id (NSNumber, given as NSString to this function) I don't get a result unless I save the whole context first. I don;t want to do that as it takes too much time (as it is a large set of data). The code is:
- (DOSite *) findSite:(NSString *) siteId {
NSPredicate* predicate = [NSPredicate predicateWithFormat:#"(id = %#)", siteId];
[NSFetchedResultsController deleteCacheWithName:nil];
[[self fetchedResultsController].fetchRequest setPredicate:predicate];
NSError *fetchError;
if (![[self fetchedResultsController] performFetch:&fetchError]) {
// Handle the error.
// This is a serious error and should advise the user to restart the application
NSLog(#"Fetching data error: %#", [fetchError localizedDescription]);
}
if([[[self fetchedResultsController] fetchedObjects] count] == 0){
return NULL;
}
return (DOSite *)[[[self fetchedResultsController] fetchedObjects] objectAtIndex:0];
}
So when I add an x number of items (using +[NSEntityDescription insertNewObjectForEntityForName:inManagedObjectContext:]) doing a search on all items return the right amount of items.
When searching for a string (e.g.predicateWithFormat:#"(name LIKE %#)") I get positive results, but when using the above code predicateWithFormat:#"(id = %#) I get zero results.
The only way I can get results is to save the whole context and then perform the fetchRequest, then suddenly it works.
So there must be something small I do wrong in searching for the id, I just seem to be blind to find it and spend two days at it now to narrow it down to this point. Is there anybody who can give me some advice on this?
This may not work, but have you tried using a name more complex than "id" in your entity (like "SiteID")? Sometimes very short names overlap with other system properties and it causes odd issues.
The problem was that I gave a NSString to the predicate as outlined above. When changing that to an int (ie predicateWithFormat:#"(id == %i)") it works fine for some reason.

iPhone SDK Core Data relationships problem

I'm having a problem with relationships between to entities in Core Data. I'm parsing some JSON and adding the entities:
if ([hourSets isKindOfClass:[NSArray class]]) { // check to see that we have got some hours back
for (NSDictionary *hourSet in hourSets) {
Hourset *thisHourSet = (Hourset *)[NSEntityDescription
insertNewObjectForEntityForName:#"Hourset"
inManagedObjectContext:managedObjectContext];
[thisHourSet setStartDate:[hourSet objectForKey:#"start_date"]];
[thisHourSet setEndDate:[hourSet objectForKey:#"end_date"]];
[record addHoursetsObject:thisHourSet];
}
}
...and then later trying to grab them again:
NSSet *hourSets = [self.listing valueForKeyPath:#"hoursets.hourset"];
NSLog(#"There are %# hourSets", [hourSets count]);
I'm getting Program received signal: “EXC_BAD_ACCESS”. when trying to access that hourSets NSSet in any way, including just counting the items in it.
Any suggestions? Pretty stumped. Thanks!
I am inferring your entity graph here but:
[self.listing valueForKeyPath:#"hoursets.hourset"]
... translates to a keypath of listing.hoursets.hourset which does not appear to return a set. Both the first and last elements are singular and therefore by convention not sets.
I would suggest logging the class of the return to confirm what, if anything, you're getting back.
Update:
(Forehead slap) The problem is actually the log statement itself. It should be:
NSLog(#"There are %d hourSets", [hourSets count]);
... because count returns an NSUInteger.

iphone Core Data Unresolved error while saving

I am getting a strange error message from the core data when trying to save
but the problem that the error is not reproducible ( it appears at different times when doing different tasks)
the error message:
Unresolved error Domain=NSCocoaErrorDomain Code=1560 UserInfo=0x14f5480 "Operation could not be completed. (Cocoa error 1560.)", {
NSDetailedErrors = (
Error Domain=NSCocoaErrorDomain Code=1570 UserInfo=0x5406d70 "Operation could not be completed. (Cocoa error 1570.)",
Error Domain=NSCocoaErrorDomain Code=1570 UserInfo=0x14f9be0 "Operation could not be completed. (Cocoa error 1570.)"
);
}
and the method that generates the error is:
- (IBAction)saveAction:(id)sender {
NSError *error;
if (![[self managedObjectContext] save:&error]) {
// Handle error
NSLog(#"Unresolved error %#, %#, %#", error, [error userInfo],[error localizedDescription]);
exit(-1); // Fail
}
}
any idea for the reason of this message ? giving that it appears at random times
It means there's a mandatory property has been assigned nil. Either in your *.xcodatamodel check the "optional" box or when you are saving to the managedObjectContext make sure that your properties are filled in.
If you're getting further errors after changing your code to suit the two requirements try cleaning your build and delete the application from your iPhone Simulator/iPhone device. Your model change may conflict with the old model implementation.
Edit:
I almost forgot here's all the error codes that Core Data spits out:
Core Data Constants Reference
I had trouble with this before and I realised I unchecked the correct optional box. Such trouble finding out the problem. Good luck.
I struggled with this for a little while myself. The real problem here is that the debugging you've got isn't showing you what the problem is. The reason for this is because CoreData will put an array of NSError objects in the "top level" NSError object it returns if there is more than one problem (This is why you see error 1560, which indicates multiple problems, and an array of error 1570s). It appears that CoreData has a handful of keys it uses to stash information in the error it returns if there is an issue that will give you more useful information (Such as the entity the error occurred on, the relationship/attribute that was missing, etc). The keys you use to inspect the userInfo dictionary can be found in the reference docs here.
This is the block of code I use to get reasonable output from the error returned during a save:
NSError* error;
if(![[survey managedObjectContext] save:&error]) {
NSLog(#"Failed to save to data store: %#", [error localizedDescription]);
NSArray* detailedErrors = [[error userInfo] objectForKey:NSDetailedErrorsKey];
if(detailedErrors != nil && [detailedErrors count] > 0) {
for(NSError* detailedError in detailedErrors) {
NSLog(#" DetailedError: %#", [detailedError userInfo]);
}
}
else {
NSLog(#" %#", [error userInfo]);
}
}
It will produce output that tells you the fields that are in missing, which makes fixing the problem significantly easier to deal with.
I'm throwing this in as an answer, even though it's really more of an embellishment to Charles' snippet. The straight output from NSLog can be a mess to read and interpret, so I like to throw in some white space and call out the value of some critical 'userInfo' keys.
Here's a version of the method I've been using. ('_sharedManagedObjectContext' is a #define for '[[[UIApplication sharedApplication] delegate] managedObjectContext]'.)
- (BOOL)saveData {
NSError *error;
if (![_sharedManagedObjectContext save:&error]) {
// If Cocoa generated the error...
if ([[error domain] isEqualToString:#"NSCocoaErrorDomain"]) {
// ...check whether there's an NSDetailedErrors array
NSDictionary *userInfo = [error userInfo];
if ([userInfo valueForKey:#"NSDetailedErrors"] != nil) {
// ...and loop through the array, if so.
NSArray *errors = [userInfo valueForKey:#"NSDetailedErrors"];
for (NSError *anError in errors) {
NSDictionary *subUserInfo = [anError userInfo];
subUserInfo = [anError userInfo];
// Granted, this indents the NSValidation keys rather a lot
// ...but it's a small loss to keep the code more readable.
NSLog(#"Core Data Save Error\n\n \
NSValidationErrorKey\n%#\n\n \
NSValidationErrorPredicate\n%#\n\n \
NSValidationErrorObject\n%#\n\n \
NSLocalizedDescription\n%#",
[subUserInfo valueForKey:#"NSValidationErrorKey"],
[subUserInfo valueForKey:#"NSValidationErrorPredicate"],
[subUserInfo valueForKey:#"NSValidationErrorObject"],
[subUserInfo valueForKey:#"NSLocalizedDescription"]);
}
}
// If there was no NSDetailedErrors array, print values directly
// from the top-level userInfo object. (Hint: all of these keys
// will have null values when you've got multiple errors sitting
// behind the NSDetailedErrors key.
else {
NSLog(#"Core Data Save Error\n\n \
NSValidationErrorKey\n%#\n\n \
NSValidationErrorPredicate\n%#\n\n \
NSValidationErrorObject\n%#\n\n \
NSLocalizedDescription\n%#",
[userInfo valueForKey:#"NSValidationErrorKey"],
[userInfo valueForKey:#"NSValidationErrorPredicate"],
[userInfo valueForKey:#"NSValidationErrorObject"],
[userInfo valueForKey:#"NSLocalizedDescription"]);
}
}
// Handle mine--or 3rd party-generated--errors
else {
NSLog(#"Custom Error: %#", [error localizedDescription]);
}
return NO;
}
return YES;
}
This allows me to see the value for 'NSValidationErrorKey', which, when I encountered the issue from the OP, pointed directly to the non-optional Core Data entities that I'd forgot to set before trying to save.
The problem touched me, when I save second record to CoreData.
All not optional fields (relationship) was filled without nil as well, but in the error output I'd notice, that one of fields in first saved object had became nil. Strange a little? But the reason is quite trivial - one to one relationship which nullify first object, when I set it in the second.
So, the scheme is:
"Parent" with relationship "child" One to One
Create Child 1, set parent. Save - OK
Create Child 2, set parent. Save - Error, Child 1.Parent == nil
(behind the scene child 2 did nullify child 1 parent)
Changing the relationship in Parent from One to One to Many to One solved this task.
I had transient property of type int that wasn't optional. Obviously, when it was set to 0, 1570 error appear. Just changed all my transient properties to optional. Nil-check logic can be implemented in code if necessary.
I means that your model failed to validate, which could happen for a number of reasons: unused property in your model, missing value that's marked as required.
To get a better understanding of what exactly went wrong, put a breakpoint in a place where you are ready to save your object, and call one of the validateFor... method variants, like:
po [myObject validateForInsert]
More detailed information about the problem is in error description. Successful validation means you will get no output.
It helped me. Check this one too.
Check the optional box in your *.xcodatamodel objects