Question

I have a Core Data object with several attributes, one of which is called Category. This is a string that could take on any value, nothing that I can guarantee any knowledge of up front. I want to run a fetch that will return a list of Category values that are shared across all stored elements whose Tag value matches a given value. I'm not sure how to best describe this, so here's an example:

ObjectNumber     Tag     Category
---------------------------------
01               AAA     Red
02               AAA     Green
03               AAA     Blue

04               BBB     Blue
05               BBB     Red
06               BBB     Yellow

07               CCC     Blue
08               CCC     Yellow
09               CCC     Red

I want the results of my fetch to be a list of Categories that are shared across all objects whose Tag is in the set {AAA, BBB, CCC}, which in this case, would return ["Red", "Blue"], because those are the only categories shared among any objects whose tag is in the given set.

I'm hoping to find something that's as fast as possible, because when this app is run on a real project, there will be tens of thousands of objects in the database.

Was it helpful?

Solution

Here is a code sample I just wrote up, that should solve your filtration question.

I'm still learning the intricacies of NSFetchRequest and predicates, although it's not very complicated, after reading the documentation and experimenting.

NSArray *setoftags = [NSArray arrayWithObjects: @"AAA", @"BBB", nil];
NSFetchRequest * request;
NSMutableSet *tagcategoriesset = nil;
for (NSString *tag in setoftags) {

    request = [NSFetchRequest fetchRequestWithEntityName:@"ObjectWithCategories"];
    NSPredicate *tagPredicate = [NSPredicate predicateWithFormat:@"%K == %@", @"Tag", tag];
    request.predicate = tagPredicate;
    NSArray *objects;
    NSError *err;
    NSMutableSet *tagcategories = [[NSMutableSet alloc] initWithCapacity:1];
    if ( (objects = [self.managedObjectContext executeFetchRequest:request error:&err]) == nil) {
        // error
        NSLog(@"There was an error:\n%@", [err localizedDescription]);
    }
    else {
        // fetch request succeeded


        // Ignore any unused tags
        if ( [objects count] == 0) continue;

        // Collect the Category attribute into a mutable set
        for(NSManagedObject *obj in objects) {
            [tagcategories addObject: [(id)obj Category]];
        }

        // First assign, later intersect the tagcategories
        if (tagcategoriesset == nil) {
            tagcategoriesset = tagcategories;
        }
        else {
            [tagcategoriesset intersectSet: tagcategories];
        }
    }
}

NSArray *finalCategories = [tagcategoriesset allObjects];

Here's another SO Q&A for further discussion: using NSPredicate with a set of answers

OTHER TIPS

These are all good articles that helped me better understand NSPredicate. I highly recommend these as worthwhile reading.

Apple Documentation

NSHipster by Mattt Thompson

Using NSPredicate to Filter Data by Peter Friese


This is an example of a simple NSPredicate...

NSString *key = @"Category";
NSString *value = @"Red";
[NSPredicate predicateWithFormat:@"%K == %@", key, value]

This is an example of a more complicated NSPredicate...

NSString *key = @"Category";
NSString *value1 = @"Red";
NSString *value2 = @"Blue";
NSPredicate *predicateRed = [NSPredicate predicateWithFormat: @"%K == %@", key, value1];
NSPredicate *predicateBlue = [NSPredicate predicateWithFormat: @"%K == %@", key, value2];
NSPredicate *predicate = [NSCompoundPredicate orPredicateWithSubpredicates:@[predicateRed, predicateBlue]];

I used this format to demonstrate what can be achieved. To be clear this second example could also be more simply written...

NSPredicate *predicate = [NSPredicate predicateWithFormat: @"(%K == %@) || (%K == %@)", key, value1, key, value2];

These examples are not intended to be the solution, however are provided to demonstrate the mechanics to help you develop a solution.

Hope that helps.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top