Sorting nsfetchedresultscontroller - ios

I have this structure in a entity of core data:
ID Region SubRegion SubRegionID CellText
1 Face Mouth 2 something
2 Face Eyes 1 ...
3 Face Nose 4 ...
...
But I want my tableview (nsfetchedresultscontroller) sorted this way:
Inside each section: cells sorted by ID property
Sections in tableView: SubRegion names but sorted by SubRegionID.
How can I achieve this? By now I'm doing this but I don't know is the best practice to sort section titles by subregionID:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"DataBase" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSPredicate *requestPredicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:#"(Region like '%#')", #"Face"]];
[fetchRequest setPredicate:requestPredicate];
NSSortDescriptor *ID = [[NSSortDescriptor alloc]
initWithKey:#"ID" ascending:YES];
[fetchRequest setSortDescriptors:[NSArray arrayWithObjects: ID, nil]];
[fetchRequest setFetchBatchSize:10];
fetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:context sectionNameKeyPath:#"SubRegion"
cacheName:nil];
fetchedResultsController.delegate = self;
Thanks for your time!

There is some redundancy in your predicate. Rather than
NSPredicate *requestPredicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:#"(Region like '%#')", #"Face"]];
it should be just
NSPredicate *requestPredicate =
[NSPredicate predicateWithFormat:#"%K == %#", #"Region", #"Face"];
It might also have to do with how you set up your NSFetchedResultsController. You should set the sectionNameKeyPath as "SubRegionID", not "SubRegion". In your tableView datasource method titleForSection: you should then return the name of the subregion based on the ID.

Related

to-many relation as sectionNameKeyPath

I want to show Project such that it shows all the projects on the basis of sharedToUsers basis. Means section name with User.user_id and it should shows all the shared project with that user. but i am not able to set section value for NSFetchedResultsController properly because it is a too many relation and it is crashing on sectionNameKeyPath .
Any Help
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *theParent = [NSEntityDescription entityForName:#"Project" inManagedObjectContext:_managedObjectContext];
//the name key exsit in parent entity of project.
NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];
[fetchRequest setFetchBatchSize:10];
[fetchRequest setEntity:theParent];
[fetchRequest setPredicate:_predicate];
NSFetchedResultsController *theFetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:_managedObjectContext sectionNameKeyPath:#"ANY sharedToUsers.user_id"
cacheName:[self getCacheNameForNSFetchedResultsController]];
if you have a senario like i have then when ever you change data in the core data then try donot use to add or update relation ship items using object of parent or category object. if you had to link some thing with category then try to link from child object.
donot use this
[category addRelationShipItem:child];
use this
`[child addToCategory:category];`
when you use this then it will not triger update call in NSFetchResultController call.
Happy coding.
Hi If you want fetch the Project shared by a user you need this predicate:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *theParent = [NSEntityDescription entityForName:#"Project" inManagedObjectContext:_managedObjectContext];
NSString *userId; // If you user_id is a NSNumber change you to it.
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"ANY sharedToUsers.user_id = %#",userId];
[fetchRequest setPredicate:predicate];
Last things you are using a NSSort: name , but name it's not a Project property.

core data dynamic predicate: passing data?

Here's my scenario:
I have a "cameras" table view and a "Rolls" table view. I want to click on a camera and load it's corresponding rolls. I can't seem to get this to work. What is the proper way to pass the selected camera core data object into the predicate of the rolls table view NSFetchedResultsController?
Camera entity
relationship : rolls
Destination :Roll
Inverse : No Inverse
Roll entity
relationship : camera
Destination :Camera
Inverse : No Inverse
from roll table view controller
- (NSFetchedResultsController *)fetchedResultsController
{
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"Roll" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSSortDescriptor *sort = [[NSSortDescriptor alloc]
initWithKey:#"desc" ascending:YES];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];
[fetchRequest setFetchBatchSize:20];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"ANY camera == %#", self.selectedCamera.objectID];
[fetchRequest setPredicate:predicate];
NSFetchedResultsController *theFetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil
cacheName:nil];
self.fetchedResultsController = theFetchedResultsController;
_fetchedResultsController.delegate = self;
return _fetchedResultsController;
}
Your relationships should each have an inverse (in this case, be inverse of each other). This allows Core Data to properly manage the relationship and allows you to set it conveniently while navigating it in both directions. It also properly represents the relationship.
The predicate should be:
NSPredicate *p = [NSPredicate predicateWithFormat:#"camera == %#", self.selectedCamera];
to use the camera relationship on the Roll entity and check that it contains the provided self.selectedCamera entity instance.

Predicate Problems

I have a managed object with the field of journalHeaderID. I can see via NSLog that those items are properly being placed into Core Data. To display the data I need to filter by what is relevant to the view.
So as I'm configuring my view of this data I have created an array of IDs that are relevant. When I run the code, though, I get no results even though I know they are there.
I thought this predicate was the right one to use, but it's not working right and I am not sure why.
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"journalHeaderID IN %#", idsToList];
Here's the array as it passees into the predicate, and I've tried it as both NSNumber and NSString.
<__NSArrayM 0xa01af70>(
800555,
800552,
800685,
803592,
803593
)
NSFetchRequest *request = [NSFetchRequest new];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"JournalHeader" inManagedObjectContext:[[BWCoreDataHelper sharedInstance] managedObjectContext]];
[request setEntity:entity];
[request setFetchBatchSize:20];
if( idsToList.count > 0 ) {
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"journalHeaderID IN %#", idsToList];
[request setPredicate:predicate];
}
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:#"headerCreateDate" ascending:NO];
[request setSortDescriptors:#[sort]];
NSFetchedResultsController *fetchedResults = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:[[BWCoreDataHelper sharedInstance] managedObjectContext] sectionNameKeyPath:nil cacheName:nil];
self.fetchedResultsController = fetchedResults;
self.fetchedResultsController.delegate = self;
From the lack of information on what results you are getting, or even if you get the delegate message, I have one suggestion.
Call - (void)performFetch:(NSFetchRequest *)fetch on the NSFetchedResultsController with your created fetch.
If you're already doing this, then it isn't obvious.

Filter NSFetchedResultsController to get only objects with some relationship

I have two entities, A and B, and the following relationships:
A -> B - To many
B -> A - To one
In other words: A can have zero or more B and B can have only one A.
I want to use NSFetchedResultsController to show my A entries in a table view, but i want to filter the results by A -> B relationship.
To do so, i have a UISegmentedControl, if the user taps the first segment i want to show only the A entries that have at least one relationship with B, and if the second segment is tapped i want to show only the entries with no relationships with B.
I'm using CoreData's NSManagedObject, so my A object has a NSSet property with all B entries in a relationships with A.
This is how i'm instantiating my NSFetchedResultsController:
NSManagedObjectContext *context = self.managedObjectContext;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:"A" inManagedObjectContext:self.managedObjectContext];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:descriptorKey ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
[fetchRequest setEntity:entity];
NSFetchedResultsController *controller = [[NSFetchedResultsController alloc]
initWithFetchRequest:fetchRequest
managedObjectContext:context
sectionNameKeyPath:controllerKey
cacheName:nil];
NSError *error;
BOOL success = [controller performFetch:&error];
if (success) {
return controller;
}
This code get all A entries, how can i make that filter?
You need to add a predicate to your fetch request:
e.g.
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"B.#count == 0"];
[fetchRequest setPredicate:predicate];
This will filter As that don't have any related B objects.
As #Abizern mentioned in comments, you need to add a NSPredicate to your NSFetchedResultsController. The predicate would be something like:
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:#"b == %#", myVarReferenceToB]];
If you only have a unique identifier in B (lets call it identifier) instead of an object reference you could write it as:
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:#"b.identifier == %#", myVarReferenceToBIdentifier]];
This will produce your filter.
Every time the user changes the segmented control you will need to re-build the fetch or you will need to keep one NSFetchedResultsController around per segment.

Fetching contacts based on tag

I'm trying to modify a simple Core Data fetch request for contacts to only look for contacts with a relationship with a certain tag. Contact and Tag are both entities with a many-to-many relationship.
I understand with Core Data I can do this by first fetching the Tag object, and then calling tag.contact, but I don't want to do it this way as the rest of the code is dependent on the fact that the fetchResultsController returns Contact objects, not Tag objects.
If I were to do relational databasing, I could do a simple cross-table query and find all contacts with a certain tag. Is there a simple way I can replicate this via Core Data?
-(NSFetchedResultsController *) fetchedResultsController {
//if fetch controller already exists
if(_fetchedResultsController != nil) {
return _fetchedResultsController;
}
//create a new fetch request
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Contact"
inManagedObjectContext:[self managedObjectContext]];
[fetchRequest setEntity:entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"lastName"
ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
//instantiate the fetch controller with the fetch request and sort by last name into sections
_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:[self managedObjectContext] sectionNameKeyPath:nil cacheName:nil];
//declare delegate of fetch controller as self
_fetchedResultsController.delegate = self;
NSLog(#"fetchResultsController Created");
return _fetchedResultsController;
}
Use NSPredicate.
Lets say you have related Contacts with Tag by name tags and tag entity has property name.
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"ANY tags.name = [cd] %#", #"sales"];
[fetchRequest setPredicate:predicate];

Resources