2012-07-11 60 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返回true的對象,你可以這樣做:

#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或者你可以添加更多的對象要求通過。例如​​。您可以在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]; 
}