你写过
NSArray *arr = [arrayPDContent filteredArrayUsingArrayPredicate:predicate];
由于-filteredArrayUsingArrayPredicate:
不是方法 onNSMutableArray
并且“filteredArrayUsingArrayPredicate”一词的唯一搜索结果是您使用相同内容打开的两个问题,我将假设这是-filteredArrayUsingPredicate:
.
你正在使用-[NSArray filteredArrayUsingPredicate:]
你的NSMutableArray
arrayPDContent
并且你期望这会发生变异arrayPDContent
。这不是什么-filteredArrayUsingPredicate:
;这是一个方法,NSArray
并且在所有 s 上具有相同的行为NSArray
,包括NSMutableArray
s。我们可以想象它的实现是这样的:
- (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
为nil
无论何时arrayPDContent
或[self filter]
更改。
编辑,附加:
为了让您在任何时候或更改时参与设置_filteredArrayPDContent
,nil
您arrayPDContent
可以[self filter]
添加该方法
- (void)resetFilteredArrayPDContent
{
_filteredArrayPDContent = nil;
}
由于应该从您 mutatearrayPDContent
或 change的任何位置[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]
-- -- 还是点-- --notation ),而不是直接在其他地方更改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 的文档中找到。
编辑,其他选择:
该问题的最简单但最糟糕的解决方案是缓存以前的版本,arrayPDContent
并且filter
每当计算_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:
其他NSMutableArray
方法)和绑定你NSTableView
的行到NSArrayController
适当的位置。
使用这种风格,您只需-setFilterPredicate:
调用NSArrayController
from -filterOnClick:
。