0

データ行のあるフォームにNSTableがあり、フォームにボタンがあり、ボタンをクリックすると、デリゲート/メソッドを呼び出してデータをフィルタリングし、Dataをreloadします。

述語によるフィルター処理は機能し、フィルター処理された配列を返しますが、グリッドには変更されたデータが表示されません

以下に示すのは、ボタンクリックの方法です。

- (IBAction)filterOnClick(id)sender {
NSString *age = @"62";
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"Age >= ", age];
NSArray *arr = [arrayPDContent filteredArrayUsingArrayPredicate:predicate];

[gridView reloadData];

}

注:arrayPDContentは、データのロードに使用されるNSMutableArrayであり、上記のarrは必要ない場合があります。

以下に示すのは、NSMutableArrayにデータを入力するためのコードの一部です。

NSString *sAge = [NSString stringWithUTFString:sqlite3_column ....];
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectAndKeys:sAge, COLUMN_ID, nil];
[arrayPDContent addObject:dictionary];

注:MAC OS内からログインできなかったため、上記のコードの一部を入力しました

4

3 に答える 3

0

私は現在、ネイトチャンドラーによって上記に投稿された次のコードを使用しています

- (NSUInteger)numberOfRowsInTableView:(NSTableView *)tableView
{
    return [[arrayPDContent filteredArrayUsingPredicate:[self filter]] count];
}

- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)column row:(NSUInteger)row
{
    return [[[arrayPDContent filteredArrayUsingPredicate:[self filter]] objectAtIndex:row] objectForKey:COLUMN_ID];
}

フィルターは問題ありませんが、ループするとカラーボールが回転し続けます

答えの最後に向かって彼が提案したようにコードを書き直すことを除いて、誰でも簡単に実装できるアイデアを提供できますか?

- (NSArray *)filteredArrayPDContent 
{
   .....
   ....
于 2012-12-29T13:52:17.457 に答える
0

このNSArrayメソッドfilteredArrayUsingPredicate:は、フィルターを通過するレシーバー内のオブジェクトのみを含む新しい配列を作成します。その配列を保持するためにローカル変数を使用していますが、メソッドarrの最後でスコープから外れると、その配列は破棄されます(または少なくともアクセスできなくなります)filterOnClick:。おそらく、データソースメソッドはまだ参照arrayPDContentしているので、テーブルにはフィルタリングされていない配列が表示されます。

NSMutableArrayフィルタに一致するオブジェクトのみを保持するようにの内容を変更する場合は、filterUsingPredicate:代わりに必要です。(ただし、これにより他のものはすべて破棄されることに注意してください。ユーザーがフィルターをクリアした後に元のデータを再度表示する場合は、別の場所に保存する必要があります。)

1つのivar/propertyを使用して「実際の」データを保存し、別のivar / propertyを使用してフィルター結果(を使用して作成filteredArrayUsingPredicate:)を保存することを検討してください。フィルタが設定されている場合は、テーブルのデータソースメソッドに後者を参照させます。

于 2012-12-29T06:48:23.830 に答える
0

あなたが書いた

NSArray *arr = [arrayPDContent filteredArrayUsingArrayPredicate:predicate];

-filteredArrayUsingArrayPredicate:はメソッドではなく、 「filteredArrayUsingArrayPredicate」という用語の検索結果は、同じコンテンツで開いた2つの質問だけなのでNSMutableArray、これはのタイプミスであると想定し-filteredArrayUsingPredicate:ます。


あなたはあなたに使用-[NSArray filteredArrayUsingPredicate:]してNSMutableArray arrayPDContentいて、これが変化することを期待していますarrayPDContent。これは何をするかで-filteredArrayUsingPredicate:はありません。これはのメソッドであり、を含むNSArrayすべてのsで同じ動作をします。その実装は次のようなものであると想像できます。NSArrayNSMutableArray

- (NSArray *)filteredArrayUsingPredicate:(NSPredicate *)predicate
{
    NSMutableArray *mutableRes = [NSMutableArray array];
    for (id obj in self) {
        if ([predicate evalutateWithObject:obj]) {
            [mutableRes addObject:obj];
        }
    }
    return [mutableRes copy];
}

特に、-filteredArrayUsingPredicate:ターゲットがのインスタンスであっても、これによってターゲットが変更されることはありませんNSMutableArray

あなたの問題の即時の解決策は書くことです

arrayPDContent = [[arrayPDContent filteredArrayUsingPredicate:predicate] mutableCopy];

代わりに

NSArray *arr = [arrayPDContent filteredArrayUsingPredicate:predicate];

ただし、これを行うことでデータを破棄しているため、これは適切な解決策ではありません。arrayPDContentここで除外された オブジェクトはすべて失われます。

より良い解決策は、述語をプロパティとして保存することです。

@property (nonatomic) NSPredicate *filter;

の実装を変更-numberOfRowsInTableView:-tableView:objectValueForTableColumn:row:、新しいプロパティを利用します。

- (NSUInteger)numberOfRowsInTableView:(NSTableView *)tableView
{
    return [[arrayPDContent filteredArrayUsingPredicate:[self filter]] count];
}

- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)column row:(NSUInteger)row
{
    return [[[arrayPDContent filteredArrayUsingPredicate:[self filter]] objectAtIndex:row] objectForKey:COLUMN_ID];
}

それよりも

- (NSUInteger)numberOfRowsInTableView:(NSTableView *)tableView
{
    return [arrayPDContent count];
}

- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)column row:(NSUInteger)row
{
    return [[arrayPDContent objectAtIndex:row] objectForKey:COLUMN_ID];
}

フィルター処理された配列が繰り返し計算されているため、これもあまり良い解決策ではありません。さらに良い解決策は、配列をキャッシュしてプロパティを追加することです

@property (nonatomic) NSArray *filteredArrayPDContent;

getter実装を使用してテーブルビューのデリゲートに

- (NSArray *)filteredArrayPDContent
{
    if (!_filteredArrayPDContent) {
        _filteredArrayPDContent = [arrayPDContent filteredArrayUsingPredicate:[self filter]];
    }
    return _filteredArrayPDContent;
}

またはが変更されるたびにに設定_filteredArrayPDContentします。nilarrayPDContent[self filter]

編集、追加

またはが変更されるたびに設定_filteredArrayPDContentする方法の一部を取得するために、メソッドを追加できますnilarrayPDContent[self filter]

- (void)resetFilteredArrayPDContent
{
    _filteredArrayPDContent = nil;
}

このメソッドはarrayPDContent、変更または変更する場所から[self filter]呼び出す必要があるため、次の場所でこのメソッドを呼び出す必要があります。

1.-filterOnClick:

- (IBAction)filterOnClick(id)sender 
{
    NSString *age = @"62";
    [self setFilter:[NSPredicate predicateWithFormat:@"Age >= ", age]];
    [self resetFilteredArrayPDContent];

    [gridView reloadData];
}

そして、入力2. した後arrayPDContent

for (/*...*/) {
//...
    NSString *sAge = [NSString stringWithUTFString:sqlite3_column ....];
    NSDictionary *dictionary = [NSDictionary dictionaryWithObjectAndKeys:sAge, COLUMN_ID, nil];
    [arrayPDContent addObject:dictionary];
//...
}
[self resetFilteredArrayPDContent];

インスタンス変数を直接設定するか、メソッド[self setArrayPDContent:]を呼び出すか(標準の角かっこ表記または新しいドット表記を使用するかどうかに関係なく)、の値を設定するたびに-resetFilteredArrayPDContent (A)を呼び出す必要があります。また、( B )を呼び出す必要があります。変更します(、、、、または配列を変更するその他の方法を使用して)。[self arrayPDContent]self.arrayPDContent = //...arrayPDContent-addObject:-removeObject:-filterUsingPredicate:NSMutableArray

編集続き、代替

上記の代わりに、代わりに:1.の実装を変更することができます。-setFilter:

- (void)setFilter:(NSPredicate *)filter
{
    _filter = filter;
    [self resetFilteredArrayPDContent];
}

また、インスタンス変数を直接設定したり、他の場所で変更したりするのではなく、呼び出していることを確認してください-setFilter:(角[self setFilter:filter]かっこ---またはドット----表記法を使用してください) 。self.filter = filter_filter-filterOnClick:[self filter]

上記の代わり2.に、メソッドを追加することができます

- (void)addArrayPDContentObject:(id)obj
{
    [arrayPDContent addObject:obj];
    [self resetFilteredArrayPDContent];
}

ポピュレートするときにそれを呼び出しますarrayPDContent

for (/*...*/) {
//...
    NSString *sAge = [NSString stringWithUTFString:sqlite3_column ....];
    NSDictionary *dictionary = [NSDictionary dictionaryWithObjectAndKeys:sAge, COLUMN_ID, nil];
    [self addArrayPDContentObject:dictionary];
//...
}

他の種類のミューテーションについても同様のメソッドを次のように追加する必要がありますarrayPDContent

arrayPDContent特定のインデックスにオブジェクトを挿入する場合は、

- (void)insertObject:(id)obj inArrayPDContentAtIndex:(NSUInteger)index
{
    [arrayPDContent insertObject:obj atIndex:index];
    [self resetFilteredArrayPDContent];
}

と電話

[self insertObject:obj inArrayPDContentAtIndex:index];

それよりも

[arrayPDContent insertObject:obj atIndex:index];

arrayPDContent特定のインデックスからオブジェクトを削除する場合

- (void)removeObjectFromArrayPDContentAtIndex:(NSUInteger)index
{
    [arrayPDContent removeObjectAtIndex:index];
    [self resetFilteredArrayPDContent];
}

と電話

[self removeObjectFromArrayPDContentAtIndex:index];

それよりも

[arrayPDContent removeObjectAtIndex:index];

など。これらのメソッドの命名規則は、Appleのドキュメントに記載されています。

編集、追加の代替

この問題に対する最も簡単ですが最悪の解決策は、以前のバージョンをキャッシュし、現在のバージョンを以前のバージョンarrayPDContentfilter比較して計算_filteredArrayPDContentおよびチェックすることです。プロパティを追加した後

@property (nonatomic) NSArray *oldArrayPDContent;
@property (nonatomic) NSPredicate *oldFilter;

の実装を変更します-filteredArrayPDContent

- (NSArray *)filteredArrayPDContent
{
    if (![[self oldArrayPDContent] isEqualToArray:arrayPDContent] 
        || ![[[self oldFilter] predicateFormat] isEqualToString:[[self filter] predicateFormat]]) {
        _filteredArrayPDContent = [arrayPDContent filteredArrayUsingPredicate:[self filter]];
        [self setOldFilter:[self filter]];
        [self setOldArrayPDContent:[arrayPDContent copy]];
    }
    return _filteredArrayPDContent;
}

のコピーとしてoldArrayPDContent設定されていることに注意してください。 arrayPDContent

繰り返しになりますが、これはパフォーマンスを向上させるための最も迅速なドロップインの代替品かもしれませんが、想像力の範囲で最もスタイリッシュなものではありません。


より良い解決策は、コンテンツ配列に適切に境界を追加することです(これが機能するには、コンテンツ配列が不変である必要があることに注意してください。より正確には、注意せずに他のメソッドNSArrayControllerを使用することはできません)。あなたの行を適切に。-addObject:NSMutableArrayNSTableViewNSArrayController

-setFilterPredicate:このスタイルを使用すると、NSArrayControllerfromを呼び出すだけです-filterOnClick:

于 2012-12-29T06:51:29.247 に答える