我被告知我可以使用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
?
答案 0 :(得分: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 :(得分: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
,或者你可以为要传递的对象添加更多的要求。例如isOdd == true AND foo == bar
。您可以在NSPredicate
文档中了解有关NSPredicate
语法的更多信息。
答案 2 :(得分: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];
}