NSFetchedResultsController delegate callback for relationship - ios

Suppose you have two entities, one is People, the other is Location. Location has an attribute name, People has a to-one relationship to Location named location.
Then if you have an NSFetchedResultsController like below, you can't get the delegate callback when you change the Locations name.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"People"
inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"location.name"
ascending:NO];
NSArray *sortDescriptors = #[sortDescriptor];
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:self.managedObjectContext
sectionNameKeyPath:#"location.name"
cacheName:#"Master"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
I know I can fetch the Location entity and then filter it by name to solve this problem. But I'm curious about this, does the NSFetchedResultsController delegate just notify you when something changed in the entity's relationship,not the relationship's attribute.
Can anyone give me some posts about this feature. I search the web and Apple's documentation but can't find a reasonable description.

does the NSFetchedResultsController delegate just notify you when something changed in the entity's relationship,not the relationship's attribute.
Exactly. Because a change in the relationship is a change in the object that the FRC is observing. But a change in the properties of one of the objects at the other end of the relationship will not be notified to the delegate because those objects are not being observed by the FRC.

Related

Core data don't return full objects, data: <fault>

I'm trying to fetch two entities eg: Student with email attribute and Professor, both of have same parent entity eg: Person with attributes entityId, firstName and lastName i want to generate them in two sections using NSFetchedResultsController.
Here is a part from getter for fetchedResultsController
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setFetchBatchSize:20];
[fetchRequest setReturnsObjectsAsFaults:NO];
NSEntityDescription *description = [NSEntityDescription entityForName:#"Person"
inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:description];
NSSortDescriptor *firstNameDescriptor = [[NSSortDescriptor alloc] initWithKey:#"firstName" ascending:YES];
NSSortDescriptor *lastNameDescriptor = [[NSSortDescriptor alloc] initWithKey:#"lastName" ascending:YES];
[fetchRequest setSortDescriptors:#[firstNameDescriptor, lastNameDescriptor]];
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc]
initWithFetchRequest:fetchRequest
managedObjectContext:self.managedObjectContext
sectionNameKeyPath:#"entityId"
cacheName:nil];
All Students have the same entityId and all Professors too
In tableView I have two prototype cells one for Student and another for Professor.
I get two sections as expected but students are in different sections, i have printed all objects from fetchedResultsController in console like this, po [self.fetchedResultsController objectAtIndexPath: [NSIndexPath indexPathForItem:1 inSection:1]] all professors are printed with fault:
<Professor: 0x6080000befc0> (entity: Professor; id: 0xd0000000001c0002 <x-coredata://03A3ECAD-CCA7-424E-86F9-258D25372BA1/Professor/p7> ; data: <fault>)
I have forced the fetch request to return full objects using [request setReturnsObjectsAsFaults:NO] but it had no effect.
Why is it happening so?
To avoid "data fault" issue you should set this field of NSFetchRequest:
request.returnsObjectsAsFaults = NO;
To separate students from professors in two sections you can use multiple NSFetchedResultsControllers, as described here:
https://stackoverflow.com/a/2309855/1689376
To avoid duplication of your code, just create a method like this and call it twice:
- (NSFetchedResultsController) createFetchedResultsController: (NSString *) entityName {
//move your code here
}

Core data NSFetchedResultsController doesn't fetch automatically

I have a core data with NSBinaryStoreType persistent store which I init its managedObjectContext with NSPrivateQueueConcurrencyType.
I have a NSFetchedResultsController property in my singleton class which I init like that:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:NSStringFromClass([CachedURLResponse class])];
fetchRequest.sortDescriptors = #[[NSSortDescriptor sortDescriptorWithKey:#"messageId" ascending:YES]];
_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:nil];
[self.fetchedResultsController performFetch:&error];
i.e , This objectContext has only entity of one type.
When I insert or delete objects my fetchObjects stays the same.
For instance if I print
self.fetchedResultsController.fetchedObjects;
before and after the following line:
MyEntity *myEntity = [NSEntityDescription insertNewObjectForEntityForName:#"MyEntity" inManagedObjectContext:self.fetchedResultsController.managedObjectContext];
The result remains the same.
Do I need to performFetch after every time I delete or insert an object?
Is there any way to auto-fetch them?
I know about the listen to the notification solution but not sure about what event I should listen to. Please let me know if this is the correct behaviour or if you have efficient solution

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.

Is it possible to use a sectionKeyPath with NSFetchedResultsController when fetching properties with NSDictionaryResultType?

I've got a fetch request set up to retrieve some properties on 'User' items:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:entity];
[fetchRequest setResultType:NSDictionaryResultType];
[fetchRequest setPropertiesToFetch:[NSArray arrayWithObjects:companyName, firstName, lastName, completeItems, incompleteItems, objectID, nil]];
[fetchRequest setPredicate:predicate];
[fetchRequest setSortDescriptors:#[[NSSortDescriptor sortDescriptorWithKey:SortOptionCompany ascending:YES],
[NSSortDescriptor sortDescriptorWithKey:SortOptionFirstName ascending:YES]]];
[fetchRequest setFetchBatchSize:kBatchSize];
I initialize my NSFetchedResultsController:
NSFetchedResultsController *frc = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:self.context
sectionNameKeyPath:#"sectionIdentifier"
cacheName:nil];
The attribute "sectionIdentifier" is a transient property on the User entity. However, when I execute this, I get the message:
"returned nil value for section name key path 'sectionIdentifier'. Object will be placed in unnamed section"
The fetched information isn't grouped into sections as desired. Is this because I need to fetch whole NSManagedObjects for the keyPath to not be nil, or is there a way to use sectionKeyPath when retrieving dictionaries? I've also tried using setPropertiesToGroupBy: with no success.
Since there was no solution that I could find for this issue, I resorted to not using a sectionKeyPath and sorting the data into sections manually after retrieval.

Fetching specific data from a selected entry

I am new to iOS Developing, and I'm getting my feet wet in Core Data. I've got an app that I'm slowly piecing together (thanks to help from this site!), but I'm stuck on how to fetch data.
The app:
My app has two main screens, both UITableViews: A "Class List" view where they can add new classes, and an "Add My data model has two entities: Course (for class) and Student, with a to-many relationship from Course-Student. Right now I have it working so that when a I tap on a class in the "Class List" view I am taken to the "Add Students" view where I can add students to the class, but my fetch results controller is returning all students that I have added. My question: how do I format the fetch request in the "Add Students" view to fetch only those students that should belong to that class? Here is the fetched results controller I have right now:
-(NSFetchedResultsController *) fetchedResultsController {
if (_fetchedResultsController !=nil) {
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Student" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:#"name" cacheName:nil];
_fetchedResultsController.delegate = self;
return _fetchedResultsController;
}
I'm guessing it has something to do with predicates, but I haven't gotten that far in my learning. Any help at all would be appreciated. Thanks!
You are guessing right. To fetch all students that belong to a particular course,
add the following predicate to the fetch request:
Course *theCourse = ...; // your Course object
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"course = %#", theCourse];
[fetchRequest setPredicate:predicate];
(assuming that the to-one relationship from Student to Course is called "course").

Resources