2012-07-11 3 views
2

Я сказал, что я могу использовать NSPredicate дублировать результаты этого методаNSPredicate вместо тросика, чтобы фильтровать массив объектов

- (void) clearArrayOut 
{ 
    bool goAgain = false; 

    for (int j=0; j<[array count]; j++) 
    { 
     if ([[array objectAtIndex:j] someMethod] == NO) 
     { 
      [array removeObjectAtIndex:j]; 
      goAgain = true; 
      break; 
     } 
    } 

    if (goAgain) [self clearArrayOut]; 
} 

Как я могу сделать NSPredicate, который будет фильтровать массив, основанный на результаты какого-либо метода вызова пользовательского класса?

ответ

10

Чтобы сделать копию с фильтром применяется:

NSArray *filteredArray = [someArray filteredArrayUsingPredicate: 
    [NSPredicate predicateWithBlock:^(id object, NSDictionary *bindings) { 
     return [object someMethod]; // if someMethod returns YES, the object is kept 
    }]]; 

Чтобы отфильтровать NSMutableArray на месте:

[someMutableArray filterUsingPredicate: 
    [NSPredicate predicateWithBlock:^(id object, NSDictionary *bindings) { 
     return [object someMethod]; // if someMethod returns YES, the object is kept 
    }]]; 

Но я бы, вероятно, просто использовать for цикл, если бы я фильтрование небольшой массив , Тем не менее, я бы написать мой for цикл немного по-другому, чтобы избежать необходимости либо уменьшаем переменную индекса или называть себя рекурсивно:

- (void)clearArrayOut:(NSMutableArray *)array { 
    for (int i = array.count - 1; i >= 0; --i) { 
     if (![[array objectAtIndex:i] someMethod]) { 
      [array removeObjectAtIndex:i]; 
     } 
    } 
} 
1

Вы просто написать его в предикат, например, предположим, у вас есть объект с методом называется isOdd, и вы хотите, чтобы фильтровать массив включать только те объекты, которые возвращают верно для isOdd, вы можете сделать это:

#import <Foundation/Foundation.h> 

@interface barfoo : NSObject 
{ 
    int number; 
} 

- (BOOL)isOdd; 
- (id)initWithNumber:(int)number; 

@end 

@implementation barfoo 

- (NSString *)description 
{ 
    return [NSString stringWithFormat:@"%i", number]; 
} 

- (BOOL)isOdd 
{ 
    return (number % 2); 
} 
- (id)initWithNumber:(int)tnumber 
{ 
    if((self = [super init])) 
    { 
     number = tnumber; 
    } 

    return self; 
} 

@end 


int main(int argc, char *argv[]) { 
    @autoreleasepool { 
     NSMutableArray *array = [NSMutableArray array]; 
     for(int i=0; i<10; i++) 
     { 
      barfoo *foo = [[barfoo alloc] initWithNumber:i]; 
      [array addObject:[foo autorelease]]; 
     } 

     NSLog(@"%@", array); // prints 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 

     NSPredicate *predicate = [NSPredicate predicateWithFormat:@"isOdd == true"]; // This is oure predicate. isOdd must be true for objects to pass 
     NSArray *result = [array filteredArrayUsingPredicate:predicate]; 

     NSLog(@"%@", result); 
    } 
} 

конечно, это также работает наоборот, ваш предикат может также прочитать isOdd == false или вы можете добавить еще больше требований к объекту проходить. Например, isOdd == true AND foo == bar. Вы можете узнать больше о синтаксисе NSPredicate в документации NSPredicate.

1

Ваша реализация ужасно неэффективен для начала: вместо продолжения делеции рекурсивно, вы можете изменить свой цикл, чтобы не наступать, если объект был удален, как это:

- (void) clearArrayOut { 
    int j = 0; 
    while (j < [array count]) { 
     if ([[array objectAtIndex:j] someMethod] == NO) { 
      [array removeObjectAtIndex:j]; 
     } else { 
      j++; 
     } 
    } 
} 

Вы могли бы сделать то же самое вещь с использованием filterUsingPredicate:, например:

- (void) clearArrayOut { 
    NSPredicate *p = [NSPredicate predicateWithBlock:^BOOL(id obj, NSDictionary *bindings) { 
     return [obj someMethod] == NO 
    }]; 
    [array filterUsingPredicate:p]; 
} 
Смежные вопросы