Can I use a keyPath in a predicate? - iphone

For some reason, this didn't work (although the keypath does exist):
The Entity is set on the Employee.
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"department.departmentName == %#", departmentName];
[fetchRequest setPredicate:predicate];
NSError *fetchError = nil;
NSUInteger count = [moc countForFetchRequest:fetchRequest error:&fetchError]; // execution simply stops at this line, with no error or console log
Execution just stops at the last line above when asking for the count. I don't get an console log. Also I don't get any kind of exception. The execution just stops. There are no objects in the persistent store yet. So maybe it crashes because of it tries to follow a keypath in a nonexisting object? Does that make sense?
The line where GDB stops is this:
0x002a31cb <+0459> test %eax,%eax
Previously to that, I see a lot of NSSQLAdapter... calls in the stack trace. There's definitely something wrong.
Well, but when I set the Entity to the destination of the key path and then just do something like
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"departmentName == %#", departmentName];
then there is no problem and count simply is 0.

I've seen this "just stopping" behavior when you have a circular reference in your object graph. The fetch gets caught up in a loop. The compiler will usually warn you if this is the case but it doesn't stop you from running.

Make sure you also set the entity of the fetch request? with setEntity:

Related

EXC_BAD_ACCESS with NSManagedObject

i am trying to insert values in a number of tables (25 to be exact), i am able to insert records in all the table except for one, and that is because of one single Attribute, if i remove that attribute it starts saving the data into the table but when i add that attribute and try to set its value, it terminates with EXC_BAD_ACCESS.
i tried changing the name of the attribute even the table's, but didnt work. below is my code::
Ashes *ashesObj = (Ashes *)[NSEntityDescription insertNewObjectForEntityForName:#"Ashes" inManagedObjectContext:managedObjectContext];
[ashesObj setAshes_id:#""];
[ashesObj setArrangement_id:#"34"];
[ashesObj setCasket_order_date:#""];
[ashesObj setCasket_model:#""];
[ashesObj setCasket_supplier:#""];
//[ashesObj setAshes_address:#"N/A"]; (This one is causing problem)
[ashesObj setPostal_code:#"N/A"];
[ashesObj setName_client:#""];
[ashesObj setTelephone:#""];
[ashesObj setEmail:#""];
NSError *error;
if (![managedObjectContext save:&error])
{
NSLog(#"Problem saving: %#", [error localizedDescription]);
}
General best practice, ANYTIME you run into a EXEC_BAD_ACCESS immediately run your code (and the same click/code path) through Instruments using the tool Zombies.
Do this with that line of code uncommented. Your app will crash, but Instruments and Zombies will point you to the exact line of code that is causing the crash (which will be different than the one you have there).
Most likely you are accidentally over releasing an object, and for whatever reason, it's only being exposed when you execute the code above.
You can launch Instruments from XCode using the Product menu, and select Profile. Once Instruments starts up, you'll be prompted for the tool to use, select Zombies. Then once the simulator appears, execute the test case to reproduce the issue. Once the crash happens, you'll see info from Zombies.

Core Data with UIDocument: RelationShips of new Objects somwhow broken after didEnterBackground and reopen

I changed my app from a single context with sqlite store managed in the app delegate to UIManagedDocument (Like default Xcode template with Core Data activated).
Now I have some strange behavior when trying to fetch objects that has been created since the current app startup, after I closed(backgrounded) and reopened the app.
There are 2 Entities: Folder and Item.
Folder to Item is a to-many-relationship.
The predicate of my fetchedResultsController to display the items in the current folder looks like that:
[fetchRequest setEntity:[NSEntityDescription entityForName:#"Item" inManagedObjectContext:self.context]];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:#"(folder == %#)", self.currentFolder]];
This still works fine beside one situation:
- I create a new folder, add some items to it
- Then close (background) and reopen the app
- Select this folder to be displayed in the TableView
Then the fetch returns 0 results.
As soon as I kill the app and reopen it, the items of the folder are displayed again (and the fetchRequests returns the correct number of items).
I did some further testing inside the viewDidAppear with some manual fetchRequests without a fetchedResultsController.
And I really don't understand how this can happen.
Both fetchRequests are basically the same (and also identical to the fetchedResultController's one),
but the first one doesn't have the predicate and then checks in a for loop whether the item's folder ist the viewController's currentFolder.
From my understanding, this should result in the exact same behavior, but while the predicate fails after backgrounding,
the fetching of all items + testing in the for loop works fine all time.
// Returns fetchResult.count = 0 for new created folders after backgrounding the app
[fetchRequest1 setEntity:[NSEntityDescription entityForName:#"Item" inManagedObjectContext:self.context]];
[fetchRequest1 setPredicate:[NSPredicate predicateWithFormat:#"(folder == %#)", self.currentFolder]];
NSArray *fetchResult1 = [self.context executeFetchRequest:fetchRequest1 error:nil];
// This time get all items in the context withour predicate
[fetchRequest2 setEntity:[NSEntityDescription entityForName:#"Item" inManagedObjectContext:self.context]];
[fetchRequest2 setPredicate:nil];
NSArray *fetchResult2 = [self.context executeFetchRequest:fetchRequest1 error:nil];
// Filter to get only the items in the current folder
NSMutableArray *filteredFetchResults2 = [NSMutableArray mutableArrayWithCapacity:0];
for (Item *item in fetchResult2) {
if (item.folder == self.currentFolder) [filteredFetchResults2 addObject:item];
}
// filteredFetchResults2 holds the correct items even after backgrounding. Why?!?
How could that be?
I guess the answer is this somehow, as backgrounding will simply save the file:
Core Data managed object does not see related objects until restart Simulator
Lesson learned: better avoid UIManagedDocument for the moment. Even if you wanted to use it locally without iCloud.

NSPredicate problem

I'm attempting to search an array of objects using NSPredicate. The objects have a number of NSString properties that I want to filter.
I have the following code to do the filtering:
NSString *predicateString = [NSString stringWithFormat:#"name like[c] %#",self.textFieldOutlet.text];
NSPredicate *searchPredicate = [NSPredicate predicateWithFormat:predicateString];
NSArray *results = [[MySingleton sharedMySingleton].cardArray filteredArrayUsingPredicate:searchPredicate];
But I get the following error:
WebKit discarded an uncaught exception in the webView:shouldInsertText:replacingDOMRange:givenAction: delegate: <NSUnknownKeyException> [<CardObject 0x14a530> valueForUndefinedKey:]: this class is not key value coding-compliant for the key test.
If I put single quotes around the %# it works but only if the entered text is exactly the same as the value held for the name key and not if it is 'like' the value. Thus not very useful. I must be doing something wrong with the predicate string, can anyone advise?
Thanks in advance!
Apparently the error states that your object is not key-value compliant.
Try using NSDictionary instead
The error states that your CardObjects don't support the property 'test' with KVO.
However, your predicate simply asks to compare the name property so it looks like this predicate isn't the reason that your webview is crashing.
Can you add the contents of your webView:shouldInsertText:replacingDOMRange:givenAction: method to the question because that's where the bug is occurring.
I think that changing the predicate is changing the flow of the code later in this method, and that's where the error is (but without seeing the rest of your code, that's a bit of a guess!).
Ok I still have no idea why I get a webview error for the NSPredicate. But I have fixed the issue using the following predicate string:
(name like[cd] '*%#*')

Core Data: Adding objects from NSMutableArray to NSMutableSet?

Judging from the amount of related questions that were brought up, this looks like a frequently asked question which makes me all the more hesitant to ask it. I have looked at a majority of these questions but none of them seem to address the specific problem I am having trouble figuring out.
A little background information on what I'm trying to achieve, how I am going about it, and what issue I am having:
I am trying to parse an XML web service, load that data into an NSMutableArray(Or any other place from which I can access it later), and then take my data and load it into my Core Data model. The first part of this I can do, its once I have my information in the array and trying to load it into Core Data that I cannot seem to progress.
My model(simplified for this question) consists of a route entity that has a one to many relationship with a checkpoint entity. The data I would be trying to load is a variety of attribute information into my route entity, which is not included in my array, and then my list of checkpoints, which is what the array is. My problem is that I cannot reliably add my entire array of checkpoints and then save. For the static case I am using for development, I have a consistent 20 checkpoints being parsed into my NSMutableArray, of these, the most I have been able to transfer into my NSMutableSet aka the checkpoints part of my route entity is 7 before crashing with either a SIGABRT, or EXC_BAD ACCESS, or incorrect selector sent. I have been trying to figure it out for the better part of today with no luck. Now for some code:
NSManagedObjectContext *context = [appDelegate managedObjectContext];
//newRoute is the route that I am trying to create and then store persistently
newRoute = [NSEntityDescription insertNewObjectForEntityForName:#"Route" inManagedObjectContext:context];
//filling in some available attribute information
if (name.text == #"")
[newRoute setValue:[NSDate date] forKey:#"name"];
else
[newRoute setValue:name.text forKey:#"name"];
NSMutableSet *muteSet = [newRoute mutableSetValueForKey:#"myCheckpoints"];
for (int i = 0; i < [appDelegate.checkpoints count]; i++ )
{
Checkpoint *newCheckpoint = [[Checkpoint alloc] init];
[newCheckpoint setName:[[appDelegate.checkpoints objectAtIndex:i] valueForKey:#"name"]];
NSLog(#"Appending %# to set", newCheckpoint.name);
[muteSet addObject:newCheckpoint];
[newCheckpoint release];
}
//myCheckpoints is the route<-->>checkpoints relationship
[newRoute setValue:muteSet forKey:#"myCheckpoints"];
// Save the context.
NSError *error = nil;
if (![context save:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
Out of curiosity, why doesn't the following work?
NSSet *ckPtSet = [[NSSet alloc] initWithArray:appDelegate.checkpoints];
[newRoute setValue:ckPtSet forKey:#"myCheckpoints"];
As far as I understand, and this might be where the problem is... when setting the value of myCheckpoints, the expectation is to be passed an NSSet. When going through with the debugger the initialized set actually contains the 20 objects, but when I try to step past I get the incorrect selector received error again.
Anyways, thank you for taking the time to read my wall of text, if you need more to help please let me know and I will add it asap!
-Karoly
The documentation for [id<NSKeyValueCoding> mutableSetValueForKey:] states that it returns a mutable set proxy that provides read-write access to the unordered to-many relationship specified by a given key. This means that the object returned isn't necessarily an NSMutableSet instance per se, but a proxy wherein any changes you make to that object are reflected in your model's set itself.
This might be why [newRoute setValue:muteSet forKey:#"myCheckpoints"]; is giving you troubles. I find that a better way to think about it is to not have an intermediate object, but to nest calls, e.g.:
[[newRoute mutableSetValueForKey:#"myCheckpoints"] addObject:newCheckpoint];

NSFetchRequest cause SIGABRT OR EXC_BAD_ACCESS

I'm using this simple code for my fetch request
NSArray *fetchResults = [moc executeFetchRequest:request error:&error];
NSLog(#" i want show my result : %#",fetchResults); -> cause SIGABRT
If i'm using on my persistent store just after this creation, i have an error.
PS: the store was save between the populate and the request.
But if i close the app, and reopen ( in this case the store exist), i have no error.
in some case i can view this message : terminate called after throwing an instance of 'NSException'
but i can't access to this exception.
if i count the fetch results, i have a good number, it's really strange.
Thanks for help.
Okay, I have found the problem!
In the populate code, one of my relationships was insert with an autorelease.
Remove this, and now it's OK.
This is not a good solution:
NSManagedObject *relationEntity = [[NSEntityDescription insertNewObjectForEntityForName:#"picture" inManagedObjectContext:moc] autorelease];
Simply remove autorelease:
NSManagedObject *relationEntity = [NSEntityDescription insertNewObjectForEntityForName:#"picture" inManagedObjectContext:moc];
I have forgotten this in core data (don't use release, just set object to nil)!