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] '*%#*')
Related
I'm new to Xcode. what i want is read plist data locally in my program. i got
NSArrayM insertObject:atIndex:]: object cannot be nil error. Here is what i declared and my plist file. Thanks
NSMutableArray *phoneArray;
NSString *path=[[NSBundle mainBundle] pathForResource:#"PhoneList" ofType:#"plist"];
phoneArray= [[NSMutableArray alloc]initWithContentsOfFile:path];
key type
Item 0 Dictionary
Item 1 Dictionary
Items have description, name keys as type of String.
Verify your plist, there is most likely a bad value. Items in an NSArray or NSDictionary can not be null. You can use Xcode to open the plist file to verify it.
Personally I use "PlistEdit Pro", it can provide somewhat better diagnostics when the plist is invalid. There is a Free Trial here of PlistEdit Pro.
- (void)insertObject:(id)anObject atIndex:(NSUInteger)index
The object to add to the array's content. This value must not be nil.
before any input from the plist file, please check to see that the element is not nil, to avoid the excetion
In dictionary named dict the key value pair is:
"alba\U2019s window" = "A model in westindies.";
And to send objectForKey: I am getting the string like "alba's window". When I send like following:
[dict objectForKey:alba's window];
I am not getting anything, it is showing null.
For starters, you might want to make that an actual string, like so:
[dict objectForKey:#"alba's window"];
Note also that \U2019 is not '; but ’, which is a different character entirely.
And more generally, sticking to [a-zA-Z0-9]+ for dictionary keys is probably a good idea, unless you are inserting and retrieving programmatically using the exact same string as a key.
Since iOS6 onwards, a convenient method for setting and accessing the object for a key from an NSDictionary is:
//Setting the object in NSMutableDictionary
dictionary[#"someKey"] = #"someString";
//Accessing the object
NSString *str = dictionary[#"someKey"];
Make sure your dict isn't null; sending a message to a null object will silently fail and return null.
Another way to check your key/values is to simply NSLog(#"%#",dict); and this will show you the contents of the dictionary. Note that this output only shows quotes around values when the value contains a space.
Also, make sure you're using the same pairs of strings as the key - it looks like you're using "alba\U2019s window" in addition to "alba's window".
I am trying to grab a path value from an array for an NSURL to set an icon in my app. I get an
NSInvalidArgumentException', reason: '-[__NSArrayI length]: unrecognized selector sent to instance 0x5622590.
If I use an nslog I get the expected output:
NSLog(#"%#",[[wforecast.wicons objectAtIndex:0]valueForKey:#"nodeContent"]);
Which gives me:
Im setting the value as follows
NSURL *urlpath;
NSString *urls = [[wforecast.wicons objectAtIndex:0] valueForKey:#"nodeContent"];
urlpath = [NSURL URLWithString:(NSString *)urls];
I appreciate this is a longwinded way of doing things but I was trying to break up the individual components to find out what was going wrong but I am at a loss!
You have essentially the same problem as this other questioner had. You passed an object that is not an NSString where you needed to pass an NSString.
Use the debugger to determine exactly where the exception occurred. If you haven't done this, I wouldn't be so sure that the code you showed is what caused it; the debugger will tell you where the exception occurred with no room for doubt.
Once you've found where the exception occurred, you can examine the object that you passed, and look back at where you got it from. You need to fix either how you retrieve the string or how you stored it in the place you're now getting it from.
EDIT Thanks to Matt's post I now understand that I should not be trying to access 'started' as an array. However, if that is the case, I would like to know why this code appears to be working in other places. It still seems to me that this should be "one-or-the-other." It should work or it shouldn't.
ORIGINAL
I'm using the same fetch request in various parts of my code to find the most recent game:
Game *lastGame = [[[CoreDataAccess managedObjectContext] fetchObjectsForEntityName:#"Game" withPredicate:#"started == started.#max"] anyObject];
'Game' is an NSManagedObject and 'started' is a date attribute. 'started' is set exactly once per object in awakeFromInsert. It is never changed after that. Game is never directly instantiated, but it has three subclasses. I have tried making Game both abstract and concrete, but neither has any effect on this problem.
I'm using an NSManagedObjectContext category to perform the fetch, as shown on cocoa with love here http://cocoawithlove.com/2008/03/core-data-one-line-fetch.html.
The error I am getting is the following:
Serious application error. An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:. [<__NSDate 0xebb1130> valueForUndefinedKey:]: this class is not key value coding-compliant for the key #max. with userInfo {
NSTargetObjectUserInfoKey = "2010-11-06 11:16:53 GMT";
NSUnknownUserInfoKey = "#max";
}
It looks to me like the predicate might be trying to apply #max to a single NSDate, instead of all 'started' attributes in all games. I'm not sure though. I'm not very good with predicates, and it took me a lot of trial and error to make this one. I don't understand how the exact same fetch can have errors in different places, though.
The fetch is not part of an NSFetchedResultsController, but I am using a fetchedResultsController in the class where I'm getting the error. For example:
- (void)configureCell:(UITableViewCell*)cell atIndexPath:(NSIndexPath*)indexPath{
Game *game = [self.frc objectAtIndexPath:indexPath];
Game *lastGame = [[[CoreDataAccess managedObjectContext] fetchObjectsForEntityName:#"Game" withPredicate:#"started == started.#max"] anyObject]; // Sometimes we get past this line, sometimes we don't...
NSDateFormatter *format = [[NSDateFormatter alloc] init];
[format setDateFormat:#"EEE, MMM d, yyyy h:mm a"];
if (game != lastGame)
cell.detailTextLabel.text = [format stringFromDate:game.started];
else
cell.detailTextLabel.text = #"In Progress";
[format release];
...
}
and also here:
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
// Return NO if you do not want the specified item to be editable.
Game *lastGame = [[[CoreDataAccess managedObjectContext] fetchObjectsForEntityName:#"Game" withPredicate:#"started == started.#max"] anyObject];
if (lastGame == [frc objectAtIndexPath:indexPath])
return NO;
return YES;
}
This exact fetch is performed several times in several places, for example on startup, but it only crashes in one class. As I said it is intermittent, but it seems to be sometime after I create a new Game object. The game is created in one tab, and the code above is from a second tab which shows history.
I have seen a similar error here. In that case the problem was solved by restarting the computer, which finally allowed XCode to realize that the attribute had been deleted from the model. I have tried that, and I'm still experiencing the problem. I have also tried deleting and recreating the 'started' attribute in the model. I have also read the Core Data Troubleshooting Guide, but was unable to find any help there either.
Predicates are applied to one source object at a time. If your source object does not have an array property, you can't use an array operator.
In your case, the predicate says:
Look at a given "Game". If its own
"started" property is equal to its own
"started" property with the #max KVC
array operator applied, then this
predicate will be true.
This is not what you want. The only situation where you'd use a KVC array operator in a predicate is where a property on an object is an array. e.g.
Fetch every "Season" where the "games.#max.homeTeamScore > 50" (i.e. seasons where a home team scored more than 50 in a game). This would work because the "games" property on a "Season" would be an array, so games.homeTeamScore would also be an array.
However, the "started" property on a single Game is not an array. The array you want to operate on is actually the array of all games, which is not a property of a game.
The only twisted way you could access the array of all games would be to fetch the array of all games first, then apply the array operator outside the predicate and then on the inside of the predicate only apply the equality test.
i.e. fetch all games first, then refetch with:
fetchObjectsForEntityName:#"Game" withPredicate:#"started == %#", [allGames valueForKey:#"#max.started"]
But this is not the smart thing to do either.
Ultimately, the correct way to fetch the game with the latest starting date as you're trying to do, can't be done with the single line fetch method.
You'll need to create a variant of the method that allows you to setSortDescriptors: on the fetch request (to sort by "started", descending) and then setFetchLimit:1 on the fetch request to only get first result.
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: