NSOperationQueue operations filteredArrayUsingPredicate error - iphone

I have class MyOperation : NSOperation with #property (nonatomic, retain) NSString *oID;
And sometimes I need to cancel operation with specific oID. I'm trying to do this:
NSArray *operations = operationQueue.operations;
NSPredicate *predicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat: #"oID == %#", _specificID]];
NSArray *arrayOperations = [operations filteredArrayUsingPredicate: predicate];
and get error:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unable to parse the format string "oID == 0f5db97b-f127-4425-ad79-451d1f204016"'
Is it possible to filter operation from NSOperationQueue?

Your problem is that you are formatting a string, then sending that to the Predicate constructor method. It's already a formatter, and knows how to format the data you give it.
Basically, you need the format to look like:
oID == "0f5db97b-f127-4425-ad79-451d1f204016"
but you are getting
oID == 0f5db97b-f127-4425-ad79-451d1f204016
If you use the formatter by itself, you should get past this issue...
NSPredicate *predicate = [NSPredicate predicateWithFormat: #"oID == %#", _specificID];
NOTE: The predicate formatter knows it should handle strings specially, and automatically adds the extra quotation characters when you pass a string to be formatted by %#'

I'm going to guess that the operations.queue is a mutable array (logging its class returns this '__NSArrayM'). What you should try is:
NSArray *operations = [NSArray arrayWithArray:operationQueue.operations];
That said, some operation may have completed (and been removed from the mutable queue) by the time the predicate is applied to it.

Related

Unable to parse the format string nspredicate error when using apostrophe

I am getting this error when entering a keyword in my searchbox:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unable to parse the format
string "(title CONTAINS[c] 'hj'"
I enter any string ('hj' in this case) followed by an apostrophe (or containing an apostrophe
). No apostrophe - no error.
This is what I did:
(void)filter:(NSString*)keyword{
NSString* predicateString = [NSString stringWithFormat:#"(title CONTAINS[c] '%#')", keyword];
NSPredicate *predicate = [NSPredicate predicateWithFormat:predicateString];
self.filteredArray = [self.initialArray filteredArrayUsingPredicate:predicate];
}
As I said, the code works if apostrophe character is not included in keyword.
Sava, try this:
(void)filter:(NSString*)keyword{
NSString *keywordWithBackslashedApostrophes = [keyword stringByReplacingOccurrencesOfString:#"'" withString:#"\\'"];
NSString* predicateString = [NSString stringWithFormat:#"title CONTAINS[c] '%#'", keywordWithBackslashedApostrophes];
NSPredicate *predicate = [NSPredicate predicateWithFormat:predicateString];
self.filteredArray = [self.initialArray filteredArrayUsingPredicate:predicate];
}
The main difference from your code is that an apostrophe in the keyword is replaced by backslash-apostrophe.
I too had problems with this predicate filter I had customer names like O'Connor and the query used to fail. The solution suggested by Alexey Golikov works fine, but I would like to know if there is any NSPredicate class level fix for this. String operations are always a costly thing you may not want to do it until necessary.
-anoop
Try to look at this answer
You can do everything as in predicateWithFormat without the quotes
[NSPredicate predicateWithFormat:#"title CONTAINS[c] '%#'", keyword]
The problem is creating an NSString when you don't need to do that. Notice here that we don't need an NSString variable, and we removed the apostrophes from %#.
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"(title CONTAINS[c] %#)", keyword];

Searching arrays of objects with NSPredicate

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
[displayItems removeAllObjects]; //clear array to ensure no repeat info
if ([searchText length] == 0) {
displayItems = (NSMutableArray *)allItems;
}
else {
//search by item category
NSPredicate *catPredicate = [NSPredicate predicateWithFormat:#"category
CONTAINS[cd] %#",searchText];
[searchable filterUsingPredicate:catPredicate];
//further search by item name
NSPredicate *namePredicate = [NSPredicate predicateWithFormat:#"name CONTAINS[cd]
%#",searchText];
[searchable filterUsingPredicate:namePredicate];
displayItems = searchable;
searchable = (NSMutableArray *)allItems;
}
[self.searchResults reloadData];
}
This method is part of a simple searchable table view I am trying to create for a larger project. My code compiles and runs, and when i type something into the search bar the search function appears to work, but then the program crashes as soon as a second letter is typed. If I type two letters in a row, it throws 'NSInvalidArgumentException', reason: '-[_NSArrayI filterUsingPredicate:]: unrecognized selector sent to instance 0x6d6c040', but if I type one letter and then hit enter or backspace, it throws this guy 'NSInvalidArgumentException', reason: '-[_NSArrayI removeAllObjects]: unrecognized selector sent to instance 0x6a7f300' when I type a second letter.
I am pretty new to objective-c, and this has me perplexed. Any help I could get would be greatly appreciated.... :-/ Still having issues since update.
"One does not simply cast NSArray into NSMutableArray and then call NSMutableArray methods on it" - Boromir
Create a mutable copy instead, like this:
searchable = [allItems mutableCopy];
NOTE: Make sure to release searchable when you are finished with it.
You have to use NSMutableArray to call the methods.
NSArray has a method "filteredArrayusingPredicate".
The simple solution is use NSMutableArray.

Sorting an array of NSURL objects by creation date

My caches images to a directory (/Library/Caches/ImageCache/). When the directory exceeds a certain size I would like to delete the oldest file in the directory. To accomplish this task I use NSFileManager to retrieve the directory contents. I then try to sort this array by date and delete the oldest object.
My problem is that my program crashes when I try to sort the array by the key NSURLCreationDateKey.
NSFileManager *defaultFM = [NSFileManager defaultManager];
NSArray *keys = [NSArray arrayWithObjects:NSURLNameKey, NSURLCreationDateKey, nil];
NSURL *cacheDirectory = [self photoCacheDirectory]; // method that returns cache URL
NSArray *cacheContents = [defaultFM contentsOfDirectoryAtURL:cacheDirectory
includingPropertiesForKeys:keys
options:NSDirectoryEnumerationSkipsSubdirectoryDescendants
error:nil];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:NSURLCreationDateKey ascending:YES];
NSArray *sortedArray = [cacheContents sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
The program crashes on the last line. With error:
* Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[ valueForUndefinedKey:]: this class is not key value coding-compliant for the key NSURLCreationDateKey.'
EDIT : Better answer
If that doesn't work, you will have to write your own comparator block and get the dates to compare manually :(
[cacheContents sortUsingComparator:^ (NSURL *a, NSURL *b) {
// get the two dates
id da = [[a resourceValuesForKeys:[NSArray arrayWithObject:NSURLCreationDateKey] error:nil] objectForKey:NSURLCreationDateKey];
id db = [[b resourceValuesForKeys:[NSArray arrayWithObject:NSURLCreationDateKey] error:nil] objectForKey:NSURLCreationDateKey];
// compare them
return [da compare:db];
}];
(Same disclaimer still applies but I'm not even sure that will compile ;) - you get the idea though!)
Here is my first answer (included here for posterity but mostly it just shows how important it is to read the question properly :)
It's because you're getting an array of NSURL objects; these don't have a NSURLCreationDateKey property.
Try this (disclaimer - not 100% it will work)
NSString *key = [NSString stringWithFormat:#"fileAttributes.%#", NSURLCreationDateKey];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:key ascending:YES];
Your key to sort by is a property of the fileAttributes dictionary which is, in turn, a property of your enumerator.
I'm not positive about this, but I think that the contentsOfDirectoryAtURL: method returns a list of URLs which are not KVC objects. To get the property you want from the NSURL, you need to call:
getResourceValue:forKey:error:
Since this is not KVC compatible, you won't be able to use a sort descriptor, and instead need to use a routine like [cacheContents sortedArrayUsingComparator:...]

CoreData Basics Help

EDIT:
I have altered the NSPredicate as recommended so that my fetch code look like so. Having printed to the UITextView like this, when I press load it spits out the following:
<NSManagedObject: 0x1c7cf0>(entity: DatedText; id: 0x1420c0 <x - coredata://B52D4F88-0210-4AE2-9DA6-C05ED64FE389/DatedText/p12> ; data: <fault>)
So either its not getting any data data because it hasn't been saved/loaded correctly or I am trying to get the loaded result into a UITextView the incorrect way. Any ideas?
NSFetchRequest *fetch = [[NSFetchRequest alloc] init];
NSEntityDescription *testEntity = [NSEntityDescription entityForName:#"DatedText" inManagedObjectContext:self.managedObjectContext];
[fetch setEntity:testEntity];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"dateSaved == %#", datePicker.date];
[fetch setPredicate:pred];
NSError *fetchError = nil;
NSArray *fetchedObjs = [self.managedObjectContext executeFetchRequest:fetch error:&fetchError];
if (fetchError != nil) {
NSLog(#" fetchError=%#,details=%#",fetchError,fetchError.userInfo);
return nil;
}
NSString *object = [NSString stringWithFormat:#"%#",[fetchedObjs objectAtIndex:0]];
noteTextView.text = object;
I have been having all sorts of problems working out how to use Core Data, so I have gone back to basics, new window based ipad project using core data.
I have added a view and some code which doesn't work, hehe. Im basically trying to save some text to a date, then when going back to that date, the text which was previously saved will be shown again.
There's a tutorial on iPhone developer site here. And there are several sample codes with Core Data as well. These should get you started.
I checked your project and aside from having to synthesize the CoreData properties, I also just noticed you were trying to assign an NSArray to your fetch predicate, but it actually expects an NSPredicate object. You should use this instead:
NSPredicate *pred = [NSPredicate predicateWithFormat:#"(dateSaved == %#)", datePicker.date];
[fetch setPredicate:pred];
If you want to set more than 1 predicate you should do that on your predicate string i.e.
NSPredicate *pred = [NSPredicate predicateWithFormat:#"(dateSaved == %#) AND (dateSaved <= %#", datePicker.date, [NSDate date]];
Cheers,
Rog
You most likely crashing because your ivar is managedObjectContext_ but you are using self.managedObjectContext. You also need to synthesize the core data ivars even if you provide a custom getter.
You're setting your NSFetchRequest's predicate to an NSArray, not an NSPredicate.
If you had posted the actual crash, it would probably say something like an unknown selector was sent to an instance of NSArray.

How to correctly setup a NSPredicate for a to-many relationship when using Core Data?

I have a Core Data model in which a Task entity includes an optional to-many relationship ExcludedDays to the ExcludedDay entity. One of the properties of ExcludedDay is day, which is an NSDate object. The ExcludedDay entity has an inverse mandatory to-one relationship to the Task entity.
In order to fetch the tasks for a specified day, I need to make sure that the specified day does not appear as the day property of any ExludedDay entity.
I started trying
NSPredicate *dayIsNotExcludedPredicate = [NSPredicate predicateWithFormat: #"ALL excludedDays.day != %#", today];
However, despite what the documentation says, ALL does not work and the application throws an exception: Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘Unsupported predicate.
After posting the same question in this forum, I was able to devise the following predicate with the help of various people:
NSPredicate * dayIsNotExcludedPredicate = [NSPredicate predicateWithFormat: #"excludedDays.#count == 0 || (excludedDays.#count > 0 && NONE excludedDays.day == %#))", today];
While this worked at first, I have just discovered that this only works when the ExcludedDay entity contains ONLY one day. As soon as the ExcludedDay entity contains more than one day for the same task, this predicate stops working. As a result, a task is selected for a day even though the day appears as a day in the ExcludedDay entity, which is of course wrong. The problem is not tied to the property day being a NSDate object: replacing day with the corresponding NSString or equivalently with an integer, I still face the same issue and incorrect behaviour.
What is the correct way to implement the predicate in this case? May this be a bug related to the ANY aggregate operator when using core data?
Thank you in advance, this is now driving me crazy.
It turns out this is yet another problem with missing and/or inconsistent documentation.
The correct predicate in this case is the following one:
[NSPredicate predicateWithFormat:#"(excludedOccurrences.#count == 0) OR (0 == SUBQUERY(excludedOccurrences, $sub, $sub.day == %#).#count)", today]
In the predicate, a subquery is used to test if the number of related excludedOccurrences with a date matching your test date is equal to zero. However, the documentation is misleading. Here is what the Predicate Programming Guide says regarding the use of predicates in conjunction with to-many relationships.
Using Predicates with Relationships
If you use a to-many relationship, the construction of a predicate is slightly different. If you want to fetch Departments in which at least one of the employees has the first name "Matthew," for instance, you use an ANY operator as shown in the following example:
NSPredicate *predicate = [NSPredicate predicateWithFormat:
#"ANY employees.firstName like 'Matthew'"];
If you want to find Departments in which all the employees are paid more than a certain amount, you use an ALL operator as shown in the following example:
float salary = ... ;
NSPredicate *predicate = [NSPredicate predicateWithFormat:
#"ALL employees.salary > %f", salary];
Quite curious how to solve this I setup a little project and created the context you are using.
NSDate *today = [NSDate date];
NSMutableArray *objects = [NSMutableArray array];
{
NSArray *day = [NSArray arrayWithObjects:today, [today dateByAddingTimeInterval:20.0f], nil];
NSDictionary *excludedDay = [NSDictionary dictionaryWithObject:day forKey:#"day"];
NSDictionary *object = [NSDictionary dictionaryWithObject:excludedDay forKey:#"excludedDay"];
[objects addObject:object];
}
{
NSArray *day = [NSArray arrayWithObjects:[today dateByAddingTimeInterval:20.0f], nil];
NSDictionary *excludedDay = [NSDictionary dictionaryWithObject:day forKey:#"day"];
NSDictionary *object = [NSDictionary dictionaryWithObject:excludedDay forKey:#"excludedDay"];
[objects addObject:object];
}
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"NONE excludedDay.day == %#", today];
NSArray *filtered = [objects filteredArrayUsingPredicate:predicate];
NSLog(#"%#", filtered);
This gives the object when:
The day array is empty
The day array does not contain the 'today' date
This does not give the object when:
The day array contains the 'today'
It doesn't matter how many objects in the day array are