fault not getting fired on relationship end object to fetch its attribute objects.

I have an array of Location (NSManagedObject) objects called venues. each location object has a venueID attribute and a name attribute in it (as obtainted from Foursquare API).


Now, I am trying to form a predicate which looks like "location.venueID == <some venue id>" from venueID existing in current Location object in the Venues array.


the code is as follows...

        for (Location *venue in venues)
        {
            NSLog(@"venue object %@",venue);
            NSPredicate *venuePredicate = [NSPredicate predicateWithFormat:@"location.venueID = %@",venue.venueID];
            NSLog(@"venue predicate %@",venuePredicate);
            NSArray *sliceArray = [_fetchedResultsArray filteredArrayUsingPredicate:venuePredicate];
            NSLog(@"venue slice array %@",sliceArray);
            [slicesDictionary setValue:sliceArray forKey:venue.name];
        }


The predicate will be applied to a _fetchedResultsArray where the array of an entity A and Location is a relationship object. SO basically I want to filter out all A's which have location object matching the venueID provided.


my problem is I checked using breakpoints and venues array does have a list of Location objects but my predicate looks like this...


2015-08-27 10:25:45.786 AppName[6113:1779399] venue predicate location.venueID == nil


Any Help?!

this is how my venue object looks like...


2015-08-27 10:25:45.784 AppName[6113:1779399] venue object <Location: 0x1740d5b60> (entity: Location; id: 0xd000000030100002 <x-coredata://E59927FF-3F53-47F9-8512-E4856638DFA1/Location/p3076> ; data: <fault>)

]Modify the line:

  1. NSLog(@"venue predicate %@",venuePredicate);
  2. to be
  3. NSLog(@"venue predicate %@",[venuePredicate predicateFormat] );


Please let me know if that solved your problem. Thank you.

i did and the output remains the same.


venue predicate location.venueID == nil


how would chaning an nslog solve the issue?!

why does it say data <fault> ? could that be an issue? it should show me the attributes of the object, shouldnt it?


venue object <Location: 0x1700dff70> (entity: Location; id: 0xd0000000000c0008 <x-coredata://6E4477E5-8E28-4066-A194-BFFFA817CB05/Location/p3> ; data: <fault>)

I think I have identified the problem. fault is not being fired on the relationship object to fetch its attributes.


any help?

You can check out using prefetching.


Prefetching allows Core Data to obtain related objects in a single fetch (per entity), rather than incurring subsequent access to the store for each individual record as their faults are tripped. For example, given an Employee entity with a relationship to a Department entity, if you fetch all the employees then for each print out their name and the name of the department to which they belong, it may be that a fault has to be fired for each individual Department object (for more details, see Core Data Performance in Core Data Programming Guide). This can represent a significant overhead. You could avoid this by prefetching the department relationship in the Employee fetch, as illustrated in the following example:

NSEntityDescription *employeeEntity = [NSEntityDescription 
  entityForName:@"Employee" inManagedObjectContext:context]; 
NSFetchRequest *request = [[NSFetchRequest alloc] init]; 
request.entity = employeeEntity; 
request.relationshipKeyPathsForPrefetching = 
  [NSArray arrayWithObject:@"department"]];


Even if you were to get your current solution to work correctly, the approach would not be correct. You are creating an NSPredicate each time through the loop. The performance and memory build up is not going to be good. Apple has some great guidelines on solving these kinds of issues. Among them is the idea that one should get all the data you need, before entering loops. Check out the NSPredicate programmming guide under "Using Predicates".


Nota Bene - You should also check out Core Data Performance. You might want to leverage returnObjectsAsFaults to force the action but I'd recommend you restructure your loop to gather all the data before you begin searching. Fetching and creating predicates should be managed with care, (by measuring your app performance with the Core Data Instruments). If not done early and often small misqueues like the one above will not scale well.


</soapbox>


In any case. I hope this has been helpful. Please let me know if this resolves your issue or update with additional info.

Accepted Answer

TommieC thanks for the reply.


I appologise that I forgot to get back on this post but the problem was not fault not being fired. The problem was I was reseting the context at a wrong place in my code (after fetching entries!) and so the main entitiy objects stayed in memory only because i had a pointer to them (an nsarray which was used to load the table view).


As soon as I removed the reset, everything worked as expected.


In anycase, I have flagged the email I got from your response for future response in a related scenario.


Even if you were to get your current solution to work correctly, the approach would not be correct. You are creating an NSPredicate each time through the loop. The performance and memory build up is not going to be good. Apple has some great guidelines on solving these kinds of issues. Among them is the idea that one should get all the data you need, before entering loops.


I already have the main entity with me in prefetched. would that still make a difference in case of relationship end objects?


Thankyou.

I already have the main entity with me in prefetched. would that still make a difference in case of relationship end objects?


It would, prefetching explicitly will pull the appropriate object graph in one call rather than for each object. I would still recommend calling the data that you need into a predicate before you enter the loop. This will very likely reduce you memory overhead. You could then manipulate the loop collecting your objects to be updated and then saving them as a batch rather than singly. Overall you will want to take a long look at the performance material mentioned earlier in order to have the solution scale appropriately.

in my app the code shown above is executed only when the user wants to see the graph of the main entity base on the venue it belongs to. In order for him to be able to do that he has to first specify a sort criteria whicj fetches entites which only belong to those venues. for that, the view controller that asks for venues already loads all possible venues at once for the user to choose from. So they are already fetched in advance.


NOw one might ask that if the sort view controller requires all venues then why not pre fetch them. The reason is the user in the case of my app would want to see the graph only once in a few months. So it makes no sense to prefetch all data at all the time. Besides he might now wsnt to see the graph based on location at all. Location is just one of tje entities in my app.


HOpe u get it now. And my peesisten store should expect thousands of entries for an average user for just a few months of use.

sorry about the typos. Typing on the ipad *****!

fault not getting fired on relationship end object to fetch its attribute objects.
 
 
Q