【问题标题】:Indexing results from an NSFetchedResultsController索引来自 NSFetchedResultsController 的结果
【发布时间】:2011-08-26 01:06:23
【问题描述】:

我在使用来自 NSFetchedResults 控制器的混合、索引、可搜索结果集时遇到了一些问题。我将其设置为存储实体的索引 A-Z 首字母缩写,然后希望它显示数字首字母首字母(即 # 如 UILocalizedIndexCollat​​ion 所做的那样)。

如果全名以数字开头,我已经编写了将 Artist 对象的 "firstInitial" 属性保存为 NSString @"#" 的代码,并且我似乎已经在我的 UITableViewController 中使用了一半的代码自定义排序描述符。问题是它只在我退出/重新启动应用程序之前有效。

此时,提取结果中的# 部分出现在顶部。它会一直留在那里,直到我强制更改数据(添加/删除托管对象),然后搜索条目,并清除搜索(使用 searchDisplayController)。此时节重新排序将开始,#节将移至底部...

我显然遗漏了一些东西/盯着同一个代码太久了。或者,有一种更简单的方法,我不知道/在 Google 上找不到!

任何帮助将不胜感激!

谢谢

肖恩

我的 UITableViewController 中的相关代码如下。

- (void)viewDidLoad
{
    // ----------------------------------
    // Various other view set up things in here....
    // ...
    // ...
    // ----------------------------------

    NSError *error;
    if (![[self artistResultsController] performFetch:&error]) {
        // Update to handle the error appropriately.
        NSLog(@"Failed to fetch artists: %@, %@", error, [error userInfo]);
        exit(-1);  // Fail
    }

}
- (NSFetchedResultsController *)artistResultsController {

if (_artistResultsController != nil) {
    return _artistResultsController;
}

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription 
                               entityForName:@"Artist" inManagedObjectContext:_context];
[fetchRequest setEntity:entity];

NSSortDescriptor *initialSort = [[NSSortDescriptor alloc] 
                          initWithKey:@"firstInitial" 
                          ascending:YES 
                          comparator:^(id obj1, id obj2) {
                              // Various number conditions for comparison - if it's a # initial, then it's a number
                              if (![obj1 isEqualToString:@"#"] && [obj2 isEqualToString:@"#"]) return NSOrderedAscending;
                              else if ([obj1 isEqualToString:@"#"] && ![obj2 isEqualToString:@"#"]) return NSOrderedDescending;
                              if ([obj1 isEqualToString:@"#"] && [obj2 isEqualToString:@"#"]) return NSOrderedSame;
                              // Else it's a string - compare it by localized region
                              return [obj1 localizedCaseInsensitiveCompare:obj2];
                          }];

NSSortDescriptor *nameSort = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];

[fetchRequest setSortDescriptors:[NSArray arrayWithObjects:initialSort, nameSort, nil]];

[fetchRequest setFetchBatchSize:20];

NSFetchedResultsController *theFetchedResultsController = 
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest 
                                    managedObjectContext:_context 
                                      sectionNameKeyPath:@"firstInitial" 
                                               cacheName:nil];
self.artistResultsController = theFetchedResultsController;
_artistResultsController.delegate = self;

[nameSort release];
[initialSort release];
[fetchRequest release];
[_artistResultsController release];

return _artistResultsController;}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    if (tableView == self.searchDisplayController.searchResultsTableView) {
        return nil;
    } else {
        return [[[_artistResultsController sections] objectAtIndex:section] name];
    }
}

- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
    if (tableView == self.searchDisplayController.searchResultsTableView) {
        return nil;
    } else {
        return [[NSArray arrayWithObject:UITableViewIndexSearch] arrayByAddingObjectsFromArray:
                [[UILocalizedIndexedCollation currentCollation] sectionIndexTitles]];

    }
}

- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index
{
    if (tableView == self.searchDisplayController.searchResultsTableView) {
        return 0;
    } else {
        if (title == UITableViewIndexSearch) {
            [tableView scrollRectToVisible:self.searchDisplayController.searchBar.frame animated:NO];
            return -1;
        } 
        else {
            for (int i = [[_artistResultsController sections] count] -1; i >=0; i--) {
                NSComparisonResult cr = 
                [title localizedCaseInsensitiveCompare:
                 [[[_artistResultsController sections] objectAtIndex:i] indexTitle]];
                if (cr == NSOrderedSame || cr == NSOrderedDescending) {
                    return i;
                }
            }
            return 0;
        }
    }
}

编辑:忘了提 - 我的搜索过滤器在 fetchedResults 控制器上使用谓词,所以这会导致新的提取请求,就像这样

- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope {
    NSFetchRequest *aRequest = [_artistResultsController fetchRequest];

    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name BEGINSWITH[cd] %@", searchText];
    // set predicate to the request 
    [aRequest setPredicate:predicate];
    // save changes
    NSError *error = nil;
    if (![_artistResultsController performFetch:&error]) {
        NSLog(@"Failed to filter artists: %@, %@", error, [error userInfo]);
        abort();
    }  
} 

【问题讨论】:

  • 你是什么意思,“它只在我退出/重新启动应用程序之前有效。”您期望排序描述符有什么行为?
  • 由于数据本身在 coreData 中,我希望它在每次实例化 NSFetchedResultsController 时运行比较器 - 在这种情况下,应该是每次加载视图时。根据我所做的一些 NSLogging,当视图首次加载时,比较器块不会被命中——即使断点显示排序描述符是在视图加载时分配的——这解释了为什么它没有被正确排序。我想这里的问题是我如何强制获取的结果控制器最初以这种方式对我的数据进行排序?
  • 检查我的扩展答案:stackoverflow.com/a/15587961/1791090

标签: iphone objective-c uitableview core-data nsfetchedresultscontroller


【解决方案1】:

我最终以不同的方式解决了这个问题。

当您同时使用 CoreData 和 SQLite 作为后端存储时,SortDescriptors 似乎在运行自定义排序时遇到问题。我尝试了几件事; NSString 类别具有新的比较方法,上面列出的比较块,并多次刷新表以尝试使用排序标准强制更新。

最后,我无法强制排序描述符进行初始排序,所以我更改了实现。我将名字以数字开头的艺术家的 firstInitial 属性设置为“zzzz”。这意味着 CoreData 会立即正确排序(最后是数字)。

完成此操作后,我对 titleForHeaderInSection 方法进行硬编码,以便在适当的情况下返回标题的 #,如下所示:

if ([[[[_artistResultsController sections] objectAtIndex:section] indexTitle] isEqualToString:@"zzzz"]) return [NSString stringWithString:@"#"];
return [[[_artistResultsController sections] objectAtIndex:section] indexTitle];

本质上,这意味着它将数字分类到一个“zzzz”分组中,应该是最后一个,我只是忽略了那个标题,而是说标题是#。

不确定是否有更好的方法来做到这一点,但它将所有排序保留在 CoreData 中,从长远来看,这可能更高效/可扩展。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多