NSPredicate isKindOfClass only works for [myObject class] not for [MyClass class]

北战南征 提交于 2019-12-11 03:07:44

问题


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;

回答1:


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 )



回答2:


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.



来源:https://stackoverflow.com/questions/18377593/nspredicate-iskindofclass-only-works-for-myobject-class-not-for-myclass-class

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!