Можно ли отфильтровать NSArray по классу?
Есть ли способ построить предикат для фильтрации по типу класса?
В настоящее время я перебираю массив и проверяю класс каждого объекта. Может быть, есть более чистый путь?
3 ответа
Вы можете добавить категорию в NSObject, которая добавляет метод "cf_className", например так:
@interface NSObject (CFAdditions)
- (NSString *) cf_className;
@end
@implementation NSObject (CFAdditions)
- (NSString *) cf_className {
return NSStringFromClass([self class]);
}
@end
Оттуда вы можете использовать предикаты, такие как:
NSPredicate * p = [NSPredicate predicateWithFormat:@"cf_className = %@", aClass];
NSArray * filtered = [anArray filteredArrayUsingPredicate:p];
Если вы на Mac, вы можете просто использовать -[NSObject className]
вместо того, чтобы создавать категорию. У iPhone нет такого метода, поэтому нужна категория.
Вы можете напрямую сравнивать классы в своем предикате.
Но это, вероятно, не будет работать так, как вы ожидаете, если вы пытаетесь фильтровать объекты, принадлежащие к кластерам классов, или если у вас есть подклассы.
Например, NSDate
когда создается экземпляр обычно __NSCFDate
а также NSString
может быть NSCFString
а также другие конкретные частные классы.
Вероятно, лучше просто перебрать набор и использовать -isKindOfClass:
в качестве теста.
Если вы действительно хотите использовать NSPredicate
хотя ты можешь сделать это. Например, это будет фильтровать массив для всех объектов, полученных из NSString
, Если вы хотите строгое членство в классе, вы можете заменить isKindOfClass:
с isMemberOfClass:
,
Любой селектор, который реализуют все объекты в коллекции, принимает один аргумент и возвращает BOOL
должно работать, хотя
NSArray *mixedArray = {...};
NSPredicate *predicate = [NSPredicate predicateWithFormat:
@"self isKindOfClass: %@",
[NSString class]];
NSLog(@"%@", [mixedArray filteredArrayUsingPredicate:predicate]);
Начиная с iOS 4 и Mac OS 10.6, можно использовать +[NSPredicate predicateWithBlock:]
также. Например:
NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id object, NSDictionary *bindings) {
return [object isKindOfClass:[NSString class]];
}];
Это позволяет вам выражать свои предикаты исключительно в Objective-C, а не в синтаксисе предикатов, который требуется для predicateWithFormat:
,