NSPredicate search with NSDate error - ios

I'm attempting to get a list of to-do lists that have to-dos >= a certain date.
Data Model: Todolist has many Todos.
The due_at field in Todo model is a Date object.
This is the fetch request I'm using and it keeps crashing.
NSDate *now = [NSDate date];
int daysToAdd = _dueDateSlider.intValue;
NSDate *datePeriod = [now dateByAddingTimeInterval:60*60*24*daysToAdd];
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:#"Todolist"];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"todos.due_at >= %#", datePeriod];
[request setPredicate:pred];
NSError *error = nil;
NSArray *todolists = [managedObjectContext executeFetchRequest:request error:&error];
The error I am receiving is:
-[__NSArrayI compare:]: unrecognized selector sent to instance 0x1018a4c50
An uncaught exception was raised
I'm not sure why this is happening, as any other predicate search works fine. todos.due_at != nil is fine as well as todos.content like '%test%' works fine.

To get the lists that have any to-dos >= a certain date, use
[NSPredicate predicateWithFormat:#"ANY todos.due_at >= %#", datePeriod];

Related

NSPredicate to check property of first 5 objects in a Core Data Relationship

I am looking to create a predicate that can check the TypeID of the first 5 objects in a Core Data relationship.
Here is what I am trying, but it doesn't work:
int num = 5;
NSMutableArray *predicates = [[NSMutableArray alloc] init];
for (int i = 0; i < num; i++) {
[predicates addObject:[NSPredicate predicateWithFormat:#"SELF IN %# AND logs[%i].TypeID == 3", items, i]];
}
This gives the error:
error: SQLCore dispatchRequest: exception handling request:
< NSSQLFetchRequestContext: 0x281837aa0 > , Unsupported function
expression logs[0].TypeID with userInfo of (null) CoreData:
error: SQLCore dispatchRequest: exception handling request:
< NSSQLFetchRequestContext: 0x281837aa0 > , Unsupported function
expression logs[0].TypeID with userInfo of (null)
I realize I am probably doing this wrong, so is there a different way that I could be doing this using NSPredicate?
if you want only fetch 5. Set fetchLimit to 5. Maybe the following code can not run right away, but the principle is same. You can add a property or get function to assign the "logs.TypeID" like -(Int)myID {return logs[0].TypeID;} then "SELF IN %# AND myID == 3" would solve the problem.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Entity name" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF IN %# AND logs.TypeID == 3", items];
[fetchRequest setPredicate:predicate];
fetchRequest.fetchLimit = 5;
NSError *error = nil;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil) {
}
I’m not sure I understand the questions, but I don’t think it’s possible to do what you asked, at least not as worded. It doesn’t seem like it would be possible to inspect only five objects in the relationship and stop there, returning any number of matches or none at all, even if there are more in the database.
However, and I think this may be what you were getting at, it is possible to find five objects that are both in the items set and have at least one log with a typeID == 3. It can be done similar to what E.Coms proposed, except you need a subquery to handle the relationship. (I am assuming logs is a to-many relationship, either one-to-many or many-to-many).
Note that the following code has not been tested:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Entity name" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF IN %# AND SUBQUERY(logs, $log, $log.typeID == 3).#count != 0", items];
[fetchRequest setPredicate:predicate];
fetchRequest.fetchLimit = 5;
NSError *error = nil;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil) {
}

NSFetchedResultsController with NSPredicate

I am using a NSFetchedResultsController to handle the data going in and out of my UITableView. It all works fine until I put a NSPredicate on it. I need to get all Thread objects that have a relationship with at least one message that is not expired or does not have a expiration_date set yet. So I use the following predicate.
NSPredicate *threadPredicate = [NSPredicate predicateWithFormat:#"ANY messages.expiration_date == null OR ANY messages.expiration_date > %#", [NSDate date]];
Problem is that this causes the NSFetchedResultsController to act very strange. If a thread gains a new message in its messages relationship it deletes the row. It also does not insert new ones.
I am 100% sure it is the NSPredicate causing these behaviors. Without it, everything works fine I just don't have some of the data I do not want filtered out.
Below is a picture of the talked about section of my data model. I will also include the code for my NSFetchedResultsController.
/**
* Returns a NSFetchedResultsController for the unified inbox
*
* #return Controller for fetched results
*/
- (NSFetchedResultsController *)resultsControllerForUnifiedInbox
{
NSFetchRequest *threadsRequest = [NSFetchRequest fetchRequestWithEntityName:#"Thread"];
NSEntityDescription *threadModel = [NSEntityDescription entityForName:#"Thread" inManagedObjectContext:_mainManagedObjectContext];
[threadsRequest setEntity:threadModel];
NSPredicate *threadPredicate = [NSPredicate predicateWithFormat:#"ANY messages.expiration_date == null OR ANY messages.expiration_date > %#", [NSDate date]];
[threadsRequest setPredicate:threadPredicate];
NSSortDescriptor *threadSort = [NSSortDescriptor sortDescriptorWithKey:#"date" ascending:NO];
[threadsRequest setSortDescriptors:[NSArray arrayWithObject:threadSort]];
[threadsRequest setFetchBatchSize:LiftFetchControllerAtrributeBatchSize];
NSFetchedResultsController *fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:threadsRequest
managedObjectContext:_mainManagedObjectContext
sectionNameKeyPath:nil
cacheName:nil];
return fetchedResultsController;
}
I cannot explain the strange effects of the predicate that you observed, but I assume
that your predicate is not doing what you expect.
[NSPredicate predicateWithFormat:#"ANY messages.expiration_date == null OR ANY messages.expiration_date > %#", [NSDate date]];
finds all threads that have a message with expiration_date not set OR have a possible different message that is not expired. What you (probably) need instead is
[NSPredicate predicateWithFormat:#"SUBQUERY(messages, $m, $m.expiration_date == null OR $m.expiration_date > %#).#count > 0", [NSDate date]];

Core Data NSFetchrequest integer

I have the following scenario. I have an app that handles data by using Core Data. I have an entity called "Brothers" which has 3 attributes: Name, Status, Age.
lets say that I have 1 record on my database that has:
-Name ==> Joe (String)
-Status ==> Married (String)
-Age ==> 28 (Integer)
I have an UIlabel a UItextfield and a Button. I want to be able to type the name (in this case Joe) on the UItextfield press the button and display the age (in this case 28) in the UILabel. I would also like to store the age value into a variable type integer so I can make some calculations with it later on.
below the code that I have inside the button.
NSEntityDescription *entitydesc = [NSEntityDescription entityForName:#"Brothers" inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc]init];
[request setEntity:entitydesc];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"age %d", [self.age.text integerValue]];
[request setPredicate:predicate];
NSError *error;
NSArray *integer = [context executeFetchRequest:request error:&error];
self.displayLabel.text = integer;
Update #1
I updated the code that i have inside the button and now i am able to search by the name and display the age. I'm still looking into storing the age as an integer into a variable so i can use it later on.
NSEntityDescription *entitydesc = [NSEntityDescription entityForName:#"Brothers" inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc]init];
[request setEntity:entitydesc];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"firstname like %#", self.firstnameTextField.text];
[request setPredicate:predicate];
NSError *error;
NSArray *integer = [context executeFetchRequest:request error:&error];
if(integer.count <= 0){
self.displayLabel.text = #"No records found";
}
else {
NSString *age;
for (NSManagedObject *object in integer) {
age = [object valueForKey:#"age"];
}
self.displayLabel.text = [NSString stringWithFormat:#"age: %#",age];
}
}
A predicate is an expression. If the expression evaluates to true then the predicate is satisfied. So if you were searching by age you'd use e.g.
[NSPredicate predicateWithFormat:#"age = %d", [self.age.text integerValue]]
Or by name:
[NSPredicate predicateWithFormat:#"name = %#", someNameOrOther]
Or by both:
[NSPredicate predicateWithFormat:#"(name = %#) and (age = %d)", someNameOrOther, [self.age.text integerValue]]
A fetch request gets the actual NSManagedObjects. So you'd get back an array of Brothers. Therefore you probably want something more like this to output a name:
if([array count])
self.displayLabel.text = [array[0] name];
Or for an age:
...
self.displayLabel.text = [[array[0] age] stringValue];
Or whatever other property you're outputting.
I think your predicate is wrong, the proper format would be this:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"age.integerValue == %d", [self.age.text integerValue]];

Core data, search for objects based on objects own property

I have an NSManagedObject, foo that stores the NSDate it was created. It also has another field, lifespan which store how many seconds the object is valid for. Each foo can have a different lifespan value. Is it possible to return all foos who have not exceed their lifespan? I'm not sure how to express that in my NSPredicate or if it is even possible?
A Core Data fetch request can actually contain simple arithmetic expression.
So to find all objects where "created + lifespan >= now",
the following works:
NSDate *now = [NSDate date];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"created + lifespan >= %#", now];
Yes, it is possible.
eg:
NSDate * yesterday = [NSDate dateWithTimeIntervalSinceNow:-(60 * 60 * 24)];
NSPredicate * predicate = [[NSPredicate alloc] initWithFormat:#"dateCreated > %#", yesterday];
NSFetchRequest * fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setPredicate:predicate];
NSError * error = nil;
NSArray * results = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
Here is more info on writing predicates: http://developer.apple.com/library/ios/#DOCUMENTATION/Cocoa/Conceptual/Predicates/Articles/pCreating.html

NSPredicate Parsing

I have a simple predicate driving me crazy.
NSString *name;
NSDate *myDate;
-(void)fetch:(NSString *)name Date:(NSDate *)myDate
{
...
//predicate
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name = %# AND myDate = %#",name,myDate];
[req setPredicate:predicate];
}
-(void)fetch2:(NSString *)predicateStr
{
...
//predicate
NSPredicate *predicate = [NSPredicate predicateWithFormat:predicateStr];
[req setPredicate:predicate];
}
////// call #1/////
[self fetch:name Date:myDate]; //WORKS
////// call #2/////
NSString *predicateStr = [NSString stringWithFormat:#"name = %# AND myDate = %#",name,myDate];
[self fetch2:predicateStr];
//Call#2 doesn't work - Can't parse Date ?? Aren't they identical? The parameters are the same, no change in values. Note, the Date parameter is the problem, the NSString parameter works fine without the Date.
No, they're not the same.
For Call #1, here's what you're passing in to +predicateWithFormat::
#"name = %# AND myDate = %#"
For Call #2, here's what you're passing in to +predicateWithFormat::
#"name = Some Name AND myDate = 2012-10-17 8:05:42 PM -0800"
The first one is a valid predicate format string, and thus it works. The second is not a valid predicate format string, and thus it fails.

Resources