Why is it that [MyClass class]
fails to find the objects of the class I want in a predicate whereas [myObject class]
works? See code example below. I want to be able to find objects of type MyClass in a set without needing to have a spurious instance of the class available.
MyClass* myObject = [[MyClass alloc] init];
This doesn't work...
NSPredicate* predicate = [NSPredicate predicateWithFormat:@"self isMemberOfClass: %@", [MyClass class]];
NSArray* predicateResults = [mySet filteredSetUsingPredicate:predicate].allObjects;
This does work...
NSPredicate* predicate = [NSPredicate predicateWithFormat:@"self isMemberOfClass: %@", [myObject class]];
NSArray* predicateResults = [mySet filteredSetUsingPredicate:predicate].allObjects;
A predicate like
[NSPredicate predicateWithFormat:@"self isMemberOfClass: %@", [MyClass class]]
actually works. It returns exactly the same predicate as the (documented)
[NSComparisonPredicate
predicateWithLeftExpression:[NSExpression expressionForEvaluatedObject]
rightExpression:[NSExpression expressionForConstantValue:[MyClass class]]
customSelector:@selector(isMemberOfClass:)]
The problem in your case could be that isMemberOfClass:
compares for class equality, so this would not match objects which are members
of a subclass of MyClass
.
This could happen if MyClass
is a class cluster and myObject
is an instance
of a concrete subclass. For example:
NSString *myString = [[NSString alloc] initWithUTF8String:"hello world"];
Class c1 = [NSString class]; // NSString
Class c2 = [myString class]; // __NSCFString
BOOL b1 = [myString isMemberOfClass:c1]; // NO
BOOL b2 = [myString isMemberOfClass:c2]; // YES
In that case [myObject class]
and [MyClass class]
are different, which would explain
why one predicate works and the other predicate does not work.
The following code uses isKindOfClass:
instead and produces the expected result:
NSArray *array = @[@"123", @456, [NSArray array]];
NSPredicate* predicate = [NSPredicate predicateWithFormat:@"self isKindOfClass: %@", [NSNumber class]];
NSArray* predicateResults = [array filteredArrayUsingPredicate:predicate];
NSLog(@"%@", predicateResults);
// Output: ( 456 )
Not strictly speaking an answer to your question (see MartinR excellent answer), but an alternative to the (IMO) under documented predicateWithFormat:
method:
You could use predicateWithBlock:
to create your NSPredicate
, like so:
NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
return [evaluatedObject isKindOfClass:[myClass class]];
}];
This should work fine.