Подтвердить что ты не робот

Можно ли фильтровать NSArray по классам?

Есть ли способ построить предикат для фильтрации по типу класса?

В настоящее время я просматриваю массив и проверяю класс каждого объекта. Может быть, есть более чистый способ?

4b9b3361

Ответ 1

Вы можете добавить категорию в 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 нет этого метода, следовательно, нужна категория.

Ответ 2

Вы можете напрямую сравнивать классы и в своем предикате.

Но, вероятно, это не сработает, как вы ожидали бы, если вы пытаетесь фильтровать объекты, принадлежащие кластеру классов, или если у вас есть подклассы.

Например, NSDate при создании экземпляра обычно __NSCFDate и NSString может быть NSCFString, а также других конкретных частных классов.

Вероятно, лучше всего просто выполнить цикл через набор и использовать -isKindOfClass: в качестве теста.

IF, вы действительно хотите использовать NSPredicate, хотя вы можете это сделать. В качестве примера это будет фильтровать массив для всех объектов, полученных из NSString. Если вы хотите строгое членство в классе, вы можете заменить isKindOfClass: на isMemberOfClass:.

Любой селектор, который реализует все объекты в реализации коллекции, принимает один аргумент и возвращает BOOL.

NSArray *mixedArray = {...};
NSPredicate *predicate = [NSPredicate predicateWithFormat:
                                      @"self isKindOfClass: %@",
                                      [NSString class]];

NSLog(@"%@", [mixedArray filteredArrayUsingPredicate:predicate]);

Ответ 3

Начиная с 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:.