Getting constantValue: unrecognized selector sent to instance error - iphone

Getting this error with my fetch's predicate
2011-08-13 13:49:12.405 Codes[16957:10d03] NSlog Array: code BETWEEN {"06", "07"}
2011-08-13 13:49:12.407 Codes[16957:10d03] -[NSCFString constantValue]: unrecognized selector sent to instance 0x7464610
2011-08-13 13:49:12.409 Codes[16957:10d03] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSCFString constantValue]: unrecognized selector sent to instance 0x7464610'
NSPredicate *filterPredicate = [NSPredicate predicateWithFormat:#"ANY code BETWEEN %#", [NSArray arrayWithObjects:self.predicateFilterStart, self.predicateFilterEnd, nil]];:
NSLog shows code BETWEEN {"06", "07"}
Model Class for NSManagedObject with property code:
#interface MedicalCode : NSManagedObject
#property (nonatomic, retain) NSString * code;
#property (nonatomic, retain) NSString * codeDescription;
#property (nonatomic, retain) NSString * name;
FRC method: (ICD9Procedure is subclass of MedicalCode)
- (NSFetchedResultsController *)fetchedResultsController
{
if (__fetchedResultsController != nil)
{
return __fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"ICD9Disease" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSPredicate *myPredicate = [NSPredicate predicateWithFormat:#"ANY code BEGINSWITH[c] %#", self.predicateFilter];
[fetchRequest setPredicate:myPredicate];
[fetchRequest setFetchBatchSize:20];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"code" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
[aFetchedResultsController release];
[fetchRequest release];
[sortDescriptor release];
[sortDescriptors release];
NSError *error = nil;
if (![self.fetchedResultsController performFetch:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return __fetchedResultsController;
}
EDIT:
All I need is a predicate that filters data.
I have a property of an entity called code that is in format like 55.534.
I'm trying to fetch all data in a range, for example 50-60.

Try:
NSString *start = #"06";
NSString *end = #"07";
NSPredicate *pred = [NSPredicate predicateWithFormat:#"ANY code BETWEEN %#",
[NSArray arrayWithObjects: start, end, nil]];
NSLog(#"%#", pred);
That works for me:
2011-08-13 23:45:52.019 PredicateTest[18493:707] ANY code BETWEEN {"06", "07"}
so the error is probably in the properties.
FWIW, constantValue is a method of NSExpression. Not sure if that helps you.
I see you updated your code. Now it is very unclear where your error happened, since the code you orginally posted does not appear in the code you added, nor does it give additional info about the properties you are using.
And you say the error does not appear in the code you originally posted. It happens in a different piece of code, which you posted now, but it is not clear to me how that relates to the original code.
Update
Apparently, from the discussion inthe comments, it turns out you need numbers, so do something like:
NSPredicate *pred = [NSPredicate predicateWithFormat:#"ANY code BETWEEN %#",
[NSArray arrayWithObjects:
[NSNumber numberWithDouble: 50.0],
[NSNumber numberWithDouble: 60.0],
nil]];
Final solution
For those interested: the following apparently works.
NSPredicate *pred = [NSPredicate predicateWithFormat:#"ANY code BETWEEN %#",
[NSArray arrayWithObjects:
[NSExpression expressionForConstantValue: [NSNumber numberWithDouble: 50.0]],
[NSExpression expressionForConstantValue: [NSNumber numberWithDouble: 60.0]],
nil]];

Related

NSSortDescriptor not being called

I'm trying to execute a fetch request on an entity Folders, and I want a folder named xyz to be the last object when sorted.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"Folder" inManagedObjectContext:appDelegate.managedObjectContext];
[fetchRequest setEntity:entity];
NSSortDescriptor *lastDescriptor =
[[[NSSortDescriptor alloc] initWithKey:#"folderName" ascending:YES comparator:^NSComparisonResult(NSString* name1, NSString* name2) {
NSLog(#"descriptor");
if ([name1 isEqualToString:#"xyz"]) {
return NSOrderedAscending;
}
if ([name2 isEqualToString:#"xyz"]) {
return NSOrderedDescending;
}
return [name1 compare:name2];
}] autorelease];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:lastDescriptor]];
[fetchRequest setFetchBatchSize:5];
NSFetchedResultsController *theFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:appDelegate.managedObjectContext sectionNameKeyPath:nil cacheName:nil];
self.fetchedResultsController = theFetchedResultsController;
self.fetchedResultsController.delegate=self;
[fetchRequest release];
[theFetchedResultsController release];
NSError *error;
if (![[self fetchedResultsController] performFetch:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
exit(-1); // Fail
}
But none of the NSLog statements are being called. Are they supposed to? And the folder xyz does not appear last, but everything ends up being sorted in alphabetical order. Am I doing something wrong?
Edit: Posted full code
This code (your code) works:
- (void)sortMe {
NSDictionary *d0 = [NSDictionary dictionaryWithObject:#"efg" forKey:#"folderName"];
NSDictionary *d1 = [NSDictionary dictionaryWithObject:#"xyz" forKey:#"folderName"];
NSDictionary *d2 = [NSDictionary dictionaryWithObject:#"abc" forKey:#"folderName"];
NSDictionary *d3 = [NSDictionary dictionaryWithObject:#"def" forKey:#"folderName"];
NSArray *testMe = [NSArray arrayWithObjects:d0, d1, d2, d3, nil];
NSSortDescriptor *lastDescriptor =
[[NSSortDescriptor alloc] initWithKey:#"folderName" ascending:YES comparator:^NSComparisonResult(NSString* name1, NSString* name2) {
NSLog(#"descriptor");
if ([name1 isEqualToString:#"xyz"]) {
return NSOrderedAscending;
}
if ([name2 isEqualToString:#"xyz"]) {
return NSOrderedDescending;
}
return [name1 compare:name2];
}];
NSArray *sorted = [testMe sortedArrayUsingDescriptors:[NSArray arrayWithObject:lastDescriptor]];
for (NSDictionary *d in sorted) {
NSLog(#"value=%#", [d valueForKey:#"folderName"]);
}
}
I predict this code will work, too:
NSError *error;
NSArray *result = [appDelegate.managedObjectContext executeFetchRequest:fetchRequest error:&error];
// log the array
I think the problem is in the NSFetchedResultsController delegate setup, elsewhere in the code.

NSFetchedResultsController Creating Sections

When using the NSFetchedResultsController to create section headers for the UITableViewController the fetchedResultsController.sections has an object for each item not each section.
//Set up the request
NSManagedObjectContext *context = self.managedObjectContext;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[NSEntityDescription entityForName:#"Person"
inManagedObjectContext:context]];
[fetchRequest setFetchBatchSize:20];
NSSortDescriptor *sortDescriptor = nil;
sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"firstName"
ascending:YES];
NSArray *sortDescriptors = nil;
sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[sortDescriptor release]; sortDescriptor = nil;
[fetchRequest setSortDescriptors:sortDescriptors];
[sortDescriptors release]; sortDescriptors = nil;
//setup fetch results controller
NSFetchedResultsController *controller = nil;
controller = [[NSFetchedResultsController alloc]
initWithFetchRequest:fetchRequest
managedObjectContext:context
sectionNameKeyPath:#"firstName"
cacheName:#"PersonCache"];
__fetchedResultsController = controller;
[fetchRequest release]; fetchRequest = nil;
//IMPORTANT: Delete cache before changing predicate
[NSFetchedResultsController deleteCacheWithName:nil];
NSError *error = nil;
if (![controller performFetch:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
} else if ([[controller fetchedObjects] count] == 0){
[self retrievePeoples];
}
NSLog(#"result count: %i", [[controller fetchedObjects] count]);
NSLog(#"section count: %i", [[controller sections] count]);
NSLog(#"sectionIndexTitles count: %i", [[controller sectionIndexTitles] count]);
This returns:
result count: 18
section count: 18
sectionIndexTitles count: 13
Shouldn't the section count and the sectionIndexTitles count match? When the numberOfSectionsInTableView: and tableView:numberOfRowsInSection: methods are called I should just be able to look to the fetchedResultsController.section for a count without any additional sorting.
How do I setup the NSFetchResultsController properly to have each object in the sections array be for per section and not for all objects?
This was answered by Phillip Mills on another forum. The problem was I was using the entire firstName to create sections (not just the first letter). The fix is to update the entity to create the a section title whenever updated or changed. Apple's DateSectionTitles has a sample of what to do.

Memory leak when retrieving data from database

Hey, I've created a custom retrieval method for database access:
+(NSArray*) recordsForTable:(NSString *)table predicate:(NSPredicate *)prd{
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:table inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setPredicate:prd];
NSArray *records = [managedObjectContext executeFetchRequest:fetchRequest error:nil];
[fetchRequest release];
return records;
}
i then use the above method in this method:
-(NSArray *)tableViewControllerData{
NSNumber *savedBool = [[NSNumber alloc] initWithBool:YES];
NSString *onlyGetSavedVisitObjects = [NSString stringWithFormat:#"bolSaved=%#", savedBool];
[savedBool release];
NSMutableArray *data = [[[CoreDataAccess recordsForTable:#"LPVisit" stringPredicate:onlyGetSavedVisitObjects] mutableCopy] autorelease];
NSSortDescriptor *dateDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"dteVisitDate" ascending:NO];
NSArray *descriptors = [NSArray arrayWithObjects:dateDescriptor, nil];
[data sortedArrayUsingDescriptors:descriptors];
return data;
}
The trouble am having is that when the user makes changes to the LPVisit table and recall this method to show those changes it crashes the application.
[EDIT]
The exception it produces is:
-[__NSArrayM objectID]: unrecognized selector sent to instance 0x4dac1f0
I believe the error is at line:
NSMutableArray *data = [[[CoreDataAccess recordsForTable:#"LPVisit" stringPredicate:onlyGetSavedVisitObjects] mutableCopy] autorelease];
If I remove the autorelease, I get a memory leak but the application doesn't crash.
Does anyone have any insights, thanks in advance
Is it possible that the mutable copying is throwing the exception because *records is nil? This might happen if #"bolSaved=%#" is a typo and should be #"boolSaved=%#".

Core Data , NSFetchResultsController leaking

I am not sure if the leak is in my implementation or is it from apple's side....
Instruments indicate me that I have a leak in this line :
if (![[self fetchedResultsController]
performFetch:&error])
I am adding annotations by reading the fetchController to the Map.... like this :
-(void)fillMapWithAnnotations{
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
for(int a=0; a<[[[fetchedResultsController sections]objectAtIndex:0] numberOfObjects]; a++){
LookAround *look=(LookAround *)[fetchedResultsController objectAtIndexPath:[NSIndexPath indexPathForRow:a inSection:0]];
if(look){
AddAnnotation *newAnnotation=[[AddAnnotation alloc]initWithLookAround:look];
if(newAnnotation){
[self.mapView addAnnotation:newAnnotation];
[newAnnotation release];
newAnnotation=nil;
}
}
}
}
and I initialize my FetchController like this:
- (NSFetchedResultsController *)fetchedResultsController{
// Set up the fetched results controller if needed.
if (fetchedResultsController == nil) {
// Create the fetch request for the entity.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:#"LookAround" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
// Edit the section name key path and cache name if appropriate.
// nil for section name key path means "no sections".
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:#"Root"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
[aFetchedResultsController release];
[fetchRequest release];
[sortDescriptor release];
[sortDescriptors release];
}
return fetchedResultsController;
}
I get a leak as soon as i Navigate Back, the ViewController gets Deallocated in which I release my fetch controller object.
The objects that leak are numerous (and of the same type I guess) around the number of records in my sqlite DB
Thanks in advance for your help....
As I noted above, the leak is probably in your AddAnnotation class.

How to properly configure NSFetchedResultsController

I am placing an NSFetchedResultsController into my code so I get that nice automatic sectioning of my table view data.
So I am running a test to make sure everything works properly. I have a single Book entity in my persistent store. I will first perform the fetch the old way, then I will try to use NSFetchedResultsController. The difference between the 2 blocks of code is just 2 lines.
Code without NSFetchedResultsController:
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:kBookEntityName inManagedObjectContext:self.managedObjectContext];
[request setEntity:entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"title" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
[sortDescriptor release];
[sortDescriptors release];
//The following 2 lines will be replaced by the NSFetchedResultsController
NSMutableArray *mutableFetchResults = [[[self.managedObjectContext executeFetchRequest:request error:nil] mutableCopy] autorelease];
Book *result = (Book*)[mutableFetchResults objectAtIndex:0];
NSString* title = [result valueForKey:#"title"];
NSString* priority = [result valueForKeyPath:#"priority.name"];
[request release];
Now I substitute in the lines for the NSFetchedResultsController:
NSFetchedResultsController* fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:self.managedObjectContext sectionNameKeyPath:#"title" cacheName:#"BookList"];
Book *result = (Book*)[fetchedResultsController objectAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
Seems pretty cut and dry. The first code block properly fetches the single Book entity. The code with the NSFetchedResultsController, however, does not. Instead it returns nil.
My question is: Am I properly configuring the NSFetchedResultsController in this example?
(note, the fetchedObjects property of the NSFetchedResultsController is also nil)
I think you still need to tell the NSFetchedResultsController to actually perform the fetch:
NSError *error;
BOOL success = [controller performFetch:&error];
(taken from the example in the NSFetchedResultsController reference)
one other thing that seems odd: do you really want to use "title" as the sectionNameKeyPath? won't that basically create a separate section for each book?
You need to initialize your NSFetchedResultsController only once, as follows.The code assumes
NSFetchedResultsController *fetchedResultsController;
NSManagedObjectContext *managedObjectContext;
are declared in the header of your controller, and that managedObjectContext is already properly initialized.
- (void)viewDidLoad {
[super viewDidLoad];
NSError *error;
if (![[self fetchedResultsController] performFetch:&error]) {
// Handle error
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
NSLog(#"%d objects fetched", [[fetchedResultsController fetchedObjects] count]);
}
- (NSFetchedResultsController *)fetchedResultsController {
if (fetchedResultsController != nil) {
return fetchedResultsController;
}
/*
Set up the fetched results controller.
*/
// Create the fetch request for the entity.
NSFetchRequest *request = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:kBookEntityName inManagedObjectContext:self.managedObjectContext];
[request setEntity:entity];
/* Optional settings
[request setResultType:NSManagedObjectResultType];
[request setIncludesPropertyValues:YES];
[request setIncludesPendingChanges:NO];
[request setReturnsObjectsAsFaults:NO];
*/
// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"title" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
[sortDescriptor release];
[sortDescriptors release];;
// Edit the section name key path and cache name if appropriate.
// nil for section name key path means "no sections".
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:managedObjectContext sectionNameKeyPath:#"title" cacheName:#"BookList"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
[aFetchedResultsController release];
[request release];
return fetchedResultsController;
}