3

NSPredicates に関するいくつかのトピックについて StackOverflow を確認しました。それらはすべて正しい方向を指していますが、すべてについて重要な何かが欠けているに違いありません。

製品のリストを含む NSMutableArray があります。各製品には、ブランド、カテゴリ、タイプなどのいくつかのプロパティがあります。

ここで、ユーザーが NSPredicates を使用してその NSMutableArray をフィルタリングできるようにしたいので、選択したフィルターのいずれかが空白の場合、そのフィルターを使用しないでください。

ただし、たとえば、すべてのフィルターがオンになっている場合: カテゴリー B およびタイプ C のブランド A でフィルターすると、カテゴリー B およびタイプ C のブランド A のみが表示されます。

次にカテゴリ B の選択を解除すると、タイプ C のブランド A がフィルタされます。

私はいくつかのコードを書きましたが、主に空の NSMutableArray を返すので、NSPredicates がオフになっていると思います。

また、述語を実行する前に「すべての製品」の NSMutableArray をデフォルトにする必要があることもわかりました。そうしないと、新しいフィルター オプションが選択されたときに、既にフィルター処理された配列がフィルター処理されます。いくつかの BOOLean マジックで複数の配列を使用する必要がありますか、またはこれは NSPredicates を使用して解決できる問題ですか?

これが私のコードです:

-(void)filterTable
{
    NSPredicate *brandPredicate;
    NSPredicate *categoryPredicate;
    NSMutableArray *compoundPredicateArray;

    if( ![self.selectedBrand isEqual: @"Show All Brands"] || !(self.currentBrand == NULL))
    {
    brandPredicate = [NSPredicate predicateWithFormat:@"brand CONTAINS[cd] %@",self.currentBrand];
    compoundPredicateArray = [ NSMutableArray arrayWithObject: brandPredicate ];
    }

    if( ![self.currentCategory isEqual: @"Show All Categories"] || !(self.currentCategory == NULL)) 
    {
        categoryPredicate = [NSPredicate predicateWithFormat:@"category CONTAINS[cd] %@",self.currentCategory];
        [ compoundPredicateArray addObject: categoryPredicate];
    }

    NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:
                              compoundPredicateArray ];

    [self.tableData filterUsingPredicate:predicate];
    [self.popNTwinBee dismissPopoverAnimated:YES]; // PopoverController
    [self.tableView reloadData];
}
4

2 に答える 2

4

コードにいくつかの概念的なエラーがあります。

まず、述語の NSMutableArray を宣言するときに初期化する必要があります。

NSMutableArray *compoundPredicateArray = [NSMutableArray array];

現時点では、最初if()の 内でのみインスタンス化するため、ブランド フィルターが設定されていない場合、可変配列はインスタンス化されないため、後で (たとえば 2 番目のフィルター処理でif()) オブジェクトを追加しても効果がなく、複合述語が空で作成されます。 . 最初の内部には、次のif()ものがあります。

[compoundPredicateArray addObject:brandPredicate];

2 番目の問題は、ご想像のとおり、 を使用すると、以前にフィルター処理したものをフィルター処理していることですfilterUsingPredicate

あなたがしなければならないことは、フィルタリングされていないデータを常に に保持し、NSArrayそのメソッドを使用して、データを表示するために使用するfilteredArrayUsingPredicate新しいフィルタリングされたデータを取得することです。NSArray

于 2013-02-27T09:31:13.503 に答える
1

さて、私はコードをよく見て、これを思いつきました:

この便利な小さなコード ブロックをこのサイトから入手しました。

NSArray+filter.h

#import <Foundation/Foundation.h>

@interface NSArray (Filter)
- (NSArray*)filter:(BOOL(^)(id elt))filterBlock;
@end

NSArray+filter.m

#import "NSArray+filter.h"

@implementation NSArray(Filter)
- (NSArray*)filter:(BOOL(^)(id elt))filterBlock
{ // Create a new array
    id filteredArray = [NSMutableArray array]; // Collect elements matching the block condition
    for (id elt in self)
        if (filterBlock(elt))
        [filteredArray addObject:elt];
    return  filteredArray;
}
@end

それに応じて私の方法を編集しました。

TableViewController.m

- (void)filterTable {
    WebServiceStore *wss = [WebServiceStore sharedWebServiceStore];
    self.allProducts = [wss.allProductArray mutableCopy];
    NSArray *filteredOnBrand;
    NSArray *filteredOnCategory;
    NSArray *filteredOnCategoryAndBrand;

    if (![self.currentBrand isEqualToString:@"All Brands"] && !(self.currentBrand == nil)) 
    {
        filteredOnBrand = [self.allProducts filter:^(id elt) 
        {
            return [[elt brand] isEqualToString:self.currentBrand];
        }];
        [self.tableData removeAllObjects];
        [self.tableData addObjectsFromArray:filteredOnBrand];
    }

    if ([self.currentBrand isEqualToString:@"All Brands"] || self.currentBrand == nil) 
    {
        filteredOnBrand = [self.allProducts mutableCopy];
        [self.tableData removeAllObjects];
        [self.tableData addObjectsFromArray:filteredOnBrand];
    }

    if (![self.currentCategory isEqualToString:@"All Categories"] && !(self.currentCategory == nil)) 
    {
        filteredOnCategory = [self.allProducts filter:^(id elt) 
      {
            return [[elt category] isEqualToString:self.currentCategory];
      }];
        [self.tableData removeAllObjects];
        [self.tableData addObjectsFromArray:filteredOnCategory];
    }
    if (![self.currentCategory isEqualToString:@"All Categories"] && !(self.currentCategory == nil) && ![self.currentBrand isEqualToString:@"All Brands"] && !(self.currentBrand == nil)) {
        filteredOnBrand = [self.allProducts filter:^(id elt) {
            return [[elt brand] isEqualToString:self.currentBrand];
        }];
        filteredOnCategoryAndBrand = [filteredOnBrand filter:^(id elt) {
            return [[elt category] isEqualToString:self.currentCategory];
        }];
        [self.tableData removeAllObjects];
        [self.tableData addObjectsFromArray:filteredOnCategoryAndBrand];
    }
}

もちろん、後でテーブル データもリロードする必要がありますが、そのためにカスタム メソッドを使用しましたが、省略しました。

于 2013-03-06T09:02:21.557 に答える