views:

241

answers:

2

I've read the NSPredicate documentation and couldn't wrap my head around it all the way. Simple predicates I can understand, but now how do I create a predicate for the following situation:

I have an array of Foo objects. In the Foo class, one of the iVars is an NSMutableArray of Bar objects. I need to filter the array of Foo objects to get those that have a particular Bar object in its array. How?

Also, is it any easier (or possible) to find multiple Bar objects at once, or to combine several predicates that each search for a particular Bar?

+2  A: 

Your question can be divided into two questions, and I'll try to answer them in order.

  1. You can define a predicate on Foo instances that is true only when the instance's array of Bar objects contains a Bar instance matching a separate predicate. What you want is a [SUBQUERY][1] expression. A predicate string like this would match Foo instances with a fooInt value of 10 and with a Bar instance in the barArray property that has a barInt value of 1:

    @"fooInt==10 && SUBQUERY(barArray, $x, $x.barInt == 1).@count > 0"

    The general format for a SUBQUERY expression is SUBQUERY(collection, $var, predicate). A SUBQUERY expression returns a collection of objects in collection that match predicate, so taking it's @count will tell you if the Foo instance has a Bar instance that matches the subquery predicate.

  2. You can have an arbitrarily complex predicate within the SUBQUERY expression (including nested SUBQUERY expressions). Given that predicates containing SUBQUERY expressions are generally expensive to perform (they correspond roughly to a SQL JOIN), it's probably better to search for multiple Bar instances in one SUBQUERY expression using OR and then test for the appropriate @count in the result of the SUBQUERY. A predicate string like

    @"fooInt==10 && SUBQUERY(barArray, $x, $x.barInt == 1 || $x.barInt==2).@count >= 2"

    would find Foo instances that have a Bar instance with barInt==1 and a Bar instance with barInt==2 in the Foo instance's barArray.

Barry Wark
+1  A: 

I've found what I'm looking for:

@class Foo {
  int var1;
  NSArray *barObjs;
}

predicate = @"var1 == 5 AND ANY barObjs.id == 5";
Ed Marty