NSFetchedResultsController with many NSSortDescriptor - ios

in my app I am sorting an entity using only one NSSortDescriptor, but now I need to filter the data for 4 different attributes. This is the code for the current sorting, the result are all records from the entity sorted by the attribute 'displayOrder', but I need to filter the records by four other attributes(year,month,day,group), all of them integer32 except group which is string :
- (NSFetchedResultsController *)fetchedResultsController
{
if (fetchedResultsController) return fetchedResultsController;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity =
[NSEntityDescription entityForName:#"FavoriteThing"
inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSSortDescriptor *sortDescriptor =
[[NSSortDescriptor alloc] initWithKey:#"displayOrder"
ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc]
initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:managedObjectContext
sectionNameKeyPath:nil cacheName:#"ThingsCache"];
aFetchedResultsController.delegate = self;
[self setFetchedResultsController:aFetchedResultsController];
[aFetchedResultsController release];
[fetchRequest release];
[sortDescriptor release];
[sortDescriptors release];
return fetchedResultsController;
}
I have tried adding a predicate:
NSNumber *yearSearched = 1965;
NSPredicate *yearPredicate = [NSPredicate predicateWithFormat:#"todoYear = %#", yearSearched];
[fetchRequest setPredicate:yearPredicate];
But after running the app there is an error EXC_BAD_ACCESS at the line NSPredicate *yearPredicate = [NSPredicate predicateWithFormat:#"todoYear = %#", yearSearched];
Where the attribute 'todoYear' is from type Integer32

Your NSNumber creation is wrong (you're just setting the pointer to an integer). It should be:
NSNumber *yearSearched = #1965;
NSPredicate *yearPredicate = [NSPredicate predicateWithFormat:#"todoYear = %#", yearSearched];
[fetchRequest setPredicate:yearPredicate];

Related

find specific objects in managedObjectContext and calculate sum

I am trying to wrap my head around CoreData. So I am having a static tableview for statistics with labels like: "number of entries", "total distance", "total time" etc. I have my coredata entity called "Recording" and its attributes "startDate","duration",... and I would like to fetch all entries from the CURRENT week and then on one hand display the number of entries and on the other hand the total time. I know how to set up a fetch request (thank you, google)
- (NSFetchedResultsController *)fetchedResultsController
{
if (_fetchedResultsController != nil)
{
return _fetchedResultsController;
}
if (self.managedObjectContext)
{
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Recording" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"startDate" ascending:NO];
NSArray *sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *frc = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:self.managedObjectContext
sectionNameKeyPath:nil
cacheName:nil];
frc.delegate = self;
self.fetchedResultsController = frc;
NSError *error = nil;
if (![self.fetchedResultsController performFetch:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
return _fetchedResultsController;
}
but I am stuck with this special idea and I am not even sure if I need to do it with this...
I solved it now using:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc]init];
NSEntityDescription *theType = [NSEntityDescription entityForName:#"Recording" inManagedObjectContext:self.managedObjectContext];
fetchRequest.entity = theType;
NSDate *firstDayOfCurrentWeek = [self firstWeekday:[NSDate date]];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"((startDate > %#) AND (startDate <= %#))",firstDayOfCurrentWeek, [NSDate date]];
fetchRequest.predicate = predicate;
NSSortDescriptor *theDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"startDate" ascending:NO];
NSArray *sortDescriptors = [NSArray arrayWithObjects:theDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
and finding the sum/total like this:
NSFetchedResultsController *fetchedResults = self.fetchedResultsController;
NSInteger allWorkouts = [[fetchedResults fetchedObjects] count];
CGFloat totalDistance = [[[fetchedResults fetchedObjects] valueForKeyPath: #"#sum.distance"] floatValue];
Thanks for the hint with the predicate :)
NSPredicate is what you're searching for.
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreData/Articles/cdFetching.html

NSPredicate that can find an object and search attributes of the that object

The following finds all Master objects with Master.nameLast equally a passed in string. Though I want the NSPredicate to check if the object matches Master.nameLast and if this object has Master.batting.ab > 0
- (NSFetchedResultsController *)fetchedResultsController {
if(_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSManagedObjectContext *context = [self managedObjectContext];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Master" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"debut" ascending:YES];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"nameLast = [c]%#", nameLast];
[fetchRequest setPredicate:predicate];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
fetchRequest.sortDescriptors = sortDescriptors;
_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:context sectionNameKeyPath:nil cacheName:nil];
return _fetchedResultsController;
}
I want something that finds all Master objects matching the passed in string and have Master.batting.ab > 0
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"(nameLast = [c]%#) AND (ANY batting.ab > 0)", nameLast];

NSFetchController fetch with other predicate when 1ste one fails

I'm having a fetchrequest. Now I need to get "tracked" points from the database but when there are no tracked points they all need to be retrieved.
How can I do that? I now set a predicate on my fetchcontroller but when it doesn't find any tracked points it just doesn't show anything. So where can I hook up on this and then say retrieve everything...
Is there a way to listen that there is nothing found or how is this done?
EDIT:
- (NSFetchedResultsController *)fetchedResultsController {
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Rank" inManagedObjectContext:[NSManagedObjectContext MR_defaultContext]];
[fetchRequest setEntity:entity];
/* NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name == %#", #"Auto"];
[fetchRequest setPredicate:predicate];*/
NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:NO];
[fetchRequest setSortDescriptors:#[sort]];
[fetchRequest setFetchBatchSize:20];
NSFetchedResultsController *theFetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:[NSManagedObjectContext MR_defaultContext] sectionNameKeyPath:nil
cacheName:nil];
self.fetchedResultsController = theFetchedResultsController;
_fetchedResultsController.delegate = self;
return _fetchedResultsController;
}
Thanks to Larme this is the solution:
- (NSFetchedResultsController *)fetchedResultsController {
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Rank" inManagedObjectContext:[NSManagedObjectContext MR_defaultContext]];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name == %#", #"DON"];
[fetchRequest setPredicate:predicate];
NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:NO];
[fetchRequest setSortDescriptors:#[sort]];
[fetchRequest setFetchBatchSize:20];
NSFetchedResultsController *theFetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:[NSManagedObjectContext MR_defaultContext] sectionNameKeyPath:nil
cacheName:nil];
self.fetchedResultsController = theFetchedResultsController;
_fetchedResultsController.delegate = self;
if ([[_fetchedResultsController fetchedObjects] count] == 0)
{
NSLog(#"0 found");
[fetchRequest setPredicate:nil];
}
return _fetchedResultsController;
}

Core Data - Fetch last objects of an array of objects?

Using below code, I am fetching an array of emails from Core Data. I pass an array of emailId as the predicate to the fetch and it returns all emails for each of the emailIds.
However, I only need last object (or last email) of each of the emailIds in the predicate. Currently, I take the output of this fetch and use separate sorting to filter the objects I want. However, I would like the filtering in this fetch itself. Is there any way to do that?
- (NSFetchedResultsController *)getLatestEmail:(NSArray *)emailId
{
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"email_id IN %#", emailId];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Emails"
inManagedObjectContext:self.context];
[fetchRequest setEntity:entity];
[fetchRequest setPredicate:predicate];
[fetchRequest setFetchBatchSize:20];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"last_update_timestamp" ascending:NO];
NSArray *sortDescriptors = #[sortDescriptor];
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc]
initWithFetchRequest:fetchRequest
managedObjectContext:self.context
sectionNameKeyPath:nil
cacheName:#"Master"];
aFetchedResultsController.delegate = self;
self.emailFetchedResultsController = aFetchedResultsController;
NSError *error = nil;
if (![self.emailFetchedResultsController performFetch:&error])
{
NSLog(#"getLatestEmail failed %#, %#", error, [error userInfo]);
}
NSArray *emails = [[self.context executeFetchRequest:fetchRequest error:&error] mutableCopy];
return _emailFetchedResultsController;
}
I tried adding .lastobject to [[self.context executeFetchRequest:fetchRequest error:&error] mutableCopy], but didn't work. I couldn't also find any documentation that suggests that this is possible. However, I am sure, someone would have tried it before and would like to hear their opinion.
Invert your sort descriptor, then just set the batch size to 1 and the offset to zero.

How to update data available in coredata?

Here I got the value in fetchedObjects. How can I update the value in the array?
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Reserve" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
//NSSortDescriptor tells defines how to sort the fetched results
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"number" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSLog(#"sort count%d",[sortDescriptors count]);
fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:#"Root"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"(number = 100)", self.txtReserve.text];
// [fetchRequest setPredicate:predicate];
[fetchedResultsController.fetchRequest setPredicate:predicate];
self.fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
NSLog(#"Count of array::::%d",[fetchedObjects count]);
NSManagedObject *device = [fetchedObjects objectAtIndex:0];
NSLog(#"device::::%#",device);
I suggest that you read/watch some of the many books/tutorials on Core Data. You are missing a very basic understanding of the technology.
First, the objects you receive represent objects in the database, you have to know the entity descriptions to get the data. For example, the most basic way to get the "number" attribute of the "Reserve" entity would be...
[managedObject valueForKey:#"number"];
If you use Xcode (or a tool called mogenerator) you can have subclasses generated for your entities, and can more easily access the data via custom accessor methods.

Resources