如何使用第一个字符作为部分名称

我正在使用核心数据的表视图,我想使用我的每个结果的第一个字母作为部分标题(所以我可以得到部分索引的一面)。 有没有办法做到这一点的关键path? 像下面的东西,我用name.firstLetter作为sectionNameKeyPath (不幸的是,这是行不通的)。

我是否必须手动抓取每个结果的第一个字母并创build我的部分? 放置一个新的属性来放置第一个字母并将其用作sectionNameKeyPath吗?

 NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:@"name.firstLetter" cacheName:@"Root"]; 

谢谢。

**编辑:**我不知道这是否有所作为,但我的结果是日语,按片假名sorting。 我想用这些片假名作为部分索引。

您应该只传递“name”作为sectionNameKeyPath。 看到这个问题的答案 “核心数据支持与索引UITableView”。

UPDATE
该解决scheme只适用于如果你只关心快速索引标题卷轴。 在这种情况下,你不会显示节标题。 请参阅下面的示例代码。

否则,我同意refulgentis一个短暂的财产是最好的解决scheme。 另外,在创buildNSFetchedResultsController时, sectionNameKeyPath有这样的限制:

如果此关键path与fetchRequest中第一个sorting描述符指定的关键path不相同,则它们必须生成相同的相对sorting。 例如,fetchRequest中的第一个sorting描述符可以指定持久属性的关键字; sectionNameKeyPath可以为持久属性派生的瞬态属性指定一个键。

使用NSFetchedResultsController的锅炉板UITableViewDataSource实现:

 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return [[fetchedResultsController sections] count]; } - (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView { return [fetchedResultsController sectionIndexTitles]; } - (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index { return [fetchedResultsController sectionForSectionIndexTitle:title atIndex:index]; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section]; return [sectionInfo numberOfObjects]; } // Don't implement this since each "name" is its own section: //- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { // id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section]; // return [sectionInfo name]; //} 

更新2

对于新的“uppercaseFirstLetterOfName”瞬态属性,将新的string属性添加到模型中的适用实体,并选中“瞬态”框。

有几种方法来实现getter。 如果您正在生成/创build子类,则可以将其添加到子类的实现(.m)文件中。

否则,你可以在NSManagedObject上创build一个类(我把它放在我的视图控制器的实现文件的顶部,但是你可以在它自己的正确的头文件和实现文件之间进行分割):

 @interface NSManagedObject (FirstLetter) - (NSString *)uppercaseFirstLetterOfName; @end @implementation NSManagedObject (FirstLetter) - (NSString *)uppercaseFirstLetterOfName { [self willAccessValueForKey:@"uppercaseFirstLetterOfName"]; NSString *aString = [[self valueForKey:@"name"] uppercaseString]; // support UTF-16: NSString *stringToReturn = [aString substringWithRange:[aString rangeOfComposedCharacterSequenceAtIndex:0]]; // OR no UTF-16 support: //NSString *stringToReturn = [aString substringToIndex:1]; [self didAccessValueForKey:@"uppercaseFirstLetterOfName"]; return stringToReturn; } @end 

另外,在这个版本中,不要忘记像sectionNameKeyPath一样传递'uppercaseFirstLetterOfName':

 NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:@"uppercaseFirstLetterOfName" // this key defines the sections cacheName:@"Root"]; 

并且,在UITableViewDataSource实现中取消注释tableView:titleForHeaderInSection:

 - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section]; return [sectionInfo name]; } 

可能有一个更优雅的方式来做到这一点,但我最近有同样的问题,并提出了这个解决scheme。

首先,我在被称为firstLetterOfName的索引对象上定义了一个transient属性,并将getter写入该对象的.m文件。 前

 - (NSString *)uppercaseFirstLetterOfName { [self willAccessValueForKey:@"uppercaseFirstLetterOfName"]; NSString *stringToReturn = [[self.name uppercaseString] substringToIndex:1]; [self didAccessValueForKey:@"uppercaseFirstLetterOfName"]; return stringToReturn; } 

接下来,我设置了我的获取请求/实体来使用这个属性。

 NSFetchRequest *request = [[NSFetchRequest alloc] init]; NSEntityDescription *entity = [NSEntityDescription entityForName:@"Object" inManagedObjectContext:dataContext]; [request setEntity:entity]; [NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES selector:@selector(caseInsensitiveCompare:)]; NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor]; [request setSortDescriptors:sortDescriptors]; 

注意,没有什么好说的:小心使用NSFetchedResultsController – 它还没有完全被烘焙,恕我直言,除了文档中列出的简单情况之外的任何情况,你可能会更好地使用“老式”方式。

我解决了这个问题,使用NSFetchedResultsController vs UILocalizedIndexedCollat​​ion问题中提到的UILocalizedIndexCollat​​ion

优雅的方法是使“firstLetter”成为一个暂时的属性,但在实践中是缓慢的。

它的速度很慢,因为要计算一个瞬态属性,整个对象需要被logging到内存中。 如果你有很多的logging,这将是非常非常缓慢的。

快速但不雅的方法是创build一个非暂时的“firstLetter”属性,每次设置“name”属性时都会更新它。 几种方法来做到这一点:重写“setName:”评估者,覆盖“willSave”,KVO。

看到我的答案在这里类似的问题,我在这里描述如何创build本地化的sectionKey索引是持久的(因为你不能sorting在NSFetchedResultsController中的瞬态属性)。