一个用于 UITableview 和 UISearchDisplayController 的 NSFetchedResultController
Posted
技术标签:
【中文标题】一个用于 UITableview 和 UISearchDisplayController 的 NSFetchedResultController【英文标题】:One NSFetchedResultController for UITableview and UISearchDisplayController 【发布时间】:2014-01-07 12:09:53 【问题描述】:也许这是一个愚蠢的问题,但我觉得我可以改进我的项目,或者至少让它更具可读性。
这是交易。我有一个 UITableView
填充了来自服务器的数据。对于我使用MagicalRecord
和处理UITableView
的所有内容,我使用NSFetchedResultController
。到目前为止,一切都很好。当我尝试实现UISearchDisplayController
时出现问题。不使用NSFetchedResultController
,我只是从Core Data 中获取数据并将其传递给NSArray
。这是我用来排序的方法:
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:@"SELF.name contains[c] %@", searchText];
searchResults = [Group MR_findAllSortedBy:@"caseInsensitiveName" ascending:YES withPredicate:resultPredicate];
当然,所有UITableView
样板代码都填充了if
条件检查类型UITableView
。
我想我可以使用一个NSFetchedResultController
来处理这两项任务(同时填充UITableView
's)并省略这个searchResult
数组,但我不确定......所以我会很感激任何建议、提示或其他任何东西。
另一个问题是当我同时使用从其他来源填充的UITableViews
时,当我启用sections
时它们会发生冲突。简单地说,UISearchDisplayController.tableView
被父 UITableView
的 section
s 覆盖。
编辑
这里是一些用于处理搜索和填充UITableView
的代码
#pragma mark - Table View
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
// Count sections in FRC
if (tableView == self.searchDisplayController.searchResultsTableView)
return 1;
else
return [[self.groupsFRC sections] count];
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
// Count groups in each section of FRC
if (tableView == self.searchDisplayController.searchResultsTableView)
return [searchResults count];
else
return [[[self.groupsFRC sections] objectAtIndex:section] numberOfObjects];
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
// Get reusable cell
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"GroupCell"];
// If there isn't any create new one
if (cell == nil)
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"GroupCell"];
Group *group = [self determineGroupInTableViev:tableView atIndexPath:indexPath];
cell.textLabel.text = group.name;
// Checking if group has been selected earlier
if ([self.selectedGroups containsObject:@@"name" : group.name, @"id" : group.cashID])
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
else
[cell setAccessoryType:UITableViewCellAccessoryNone];
return cell;
// Adding checkmark to selected cell
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
Group *group = [self determineGroupInTableViev:tableView atIndexPath:indexPath];
// Checking if selected cell has accessory view set to checkmark and add group to selected groups array
if (selectedCell.accessoryType == UITableViewCellAccessoryNone)
selectedCell.accessoryType = UITableViewCellAccessoryCheckmark;
[self.selectedGroups addObject:@@"name" : group.name, @"id" : group.cashID];
NSLog(@"%@", self.selectedGroups);
else if (selectedCell.accessoryType == UITableViewCellAccessoryCheckmark)
selectedCell.accessoryType = UITableViewCellAccessoryNone;
[self.selectedGroups removeObject:@@"name" : group.name, @"id" : group.cashID];
NSLog(@"%@", self.selectedGroups);
// Hiding selection with animation for nice and clean effect
[tableView deselectRowAtIndexPath:indexPath animated:YES];
#pragma mark - Filtering
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:@"SELF.name contains[c] %@", searchText];
searchResults = [Group MR_findAllSortedBy:@"caseInsensitiveName" ascending:YES withPredicate:resultPredicate];
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
[self filterContentForSearchText:searchString
scope:[[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:[self.searchDisplayController.searchBar selectedScopeButtonIndex]]];
return YES;
-(void)searchDisplayController:(UISearchDisplayController *)controller didHideSearchResultsTableView:(UITableView *)tableView
// Realoading main table view when search result did hide
[self.tableView reloadData];
【问题讨论】:
如果您使用的是魔法唱片,那么您为什么要使用 Fechcontroller?最好的方法是您使用一个通用数组并获取已过滤和未过滤的数据并重新加载您的表格视图 我使用 'NSFetchedResultController' 因为它提供了运行中的人口。 提供有关您的表视图和搜索控制器的详细信息。仅使用搜索栏并根据更改更新 FRC 谓词可能更容易...... @Wain 我已经用源代码更新了我的问题。如果您想要更多内容,请告诉我。 【参考方案1】:我通常不觉得UISearchDisplayController
很有用。这是因为:
-
我已经有一个表格视图
搜索时表格视图单元格的显示应该和正常的一样
我仍然需要提供所有的表委托和数据源方法
我还是要提供搜索代理方法
因此,我通常为表格视图提供单一数据源,并根据输入的搜索条件操作该数据源。
这适用于 FRC 或简单数组。对于 FRC,编辑获取请求(谓词)和performFetch:
,其他一切都是自动的。对于数组,使用sortedArrayUsingDescriptors:
并重新加载(我有一个源数据的原始数组,以及用于表方法的另一个数组引用。第二个数组指向原始数组实例或从排序创建的新实例) .
在这两种情况下,我都有与使用UISearchDisplayController
类似的方法,但表方法中没有if
语句。任何if
语句和数据源的变异,仅在搜索方法中处理(调用频率要低得多)。
给类添加一个属性:
@property (strong, nonatomic) NSPredicate *filterPredicate;
在搜索文本中更改委托:
if (text.length > 0)
self.filterPredicate = [NSPredicate predicateWithFormat:...];
else
self.filterPredicate = nil;
[self refreshFRC];
在搜索取消时,只需将谓词置零并刷新。
还有刷新:
- (void)refreshFRC
NSFetchRequest *fetch = ...;
if (self.filterPredicate != nil)
fetch.predicate = self.filterPredicate;
self.frc.fetchRequest = fetch;
[self.frc performFetch:...];
【讨论】:
那么,如果没有UISearchDisplayController
,我该如何处理这种排序?通过提供原始表数据源?
基本上,使用UISearchBarDelegate
代替UISearchDisplayDelegate
方法,并编辑搜索内容的获取请求。从技术上讲,您可以保留搜索控制器,这是个人喜好。关键是编辑获取请求并重新获取。删除搜索控制器只会使代码更清洁恕我直言。
你的意思是搜索方法?我假设标准显示是所有组实体?
是的,主要的UITableView
包含所有组。我不知道如何处理这个UISearchBar
员工......我认为我的主表NSFetchedResultController
很好。
我想我明白了你的意思并使用单个 FRC 实现了这一点,但我仍然有一个 problem 可以重新填充。以上是关于一个用于 UITableview 和 UISearchDisplayController 的 NSFetchedResultController的主要内容,如果未能解决你的问题,请参考以下文章
将一个 NSManagedObject 用于 UITableView 部分,它与另一个 NSManagedObject 的关系用于行?
NSLayoutConstraint 用于 UITableView 上的视图
ContentInsets 不适用于 UITableView