如何使用第一个字符作为部分名称
我正在使用核心数据的表视图,我想使用我的每个结果的第一个字母作为部分标题(所以我可以得到部分索引的一面)。 有没有办法做到这一点的关键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 UILocalizedIndexedCollation问题中提到的UILocalizedIndexCollation
优雅的方法是使“firstLetter”成为一个暂时的属性,但在实践中是缓慢的。
它的速度很慢,因为要计算一个瞬态属性,整个对象需要被logging到内存中。 如果你有很多的logging,这将是非常非常缓慢的。
快速但不雅的方法是创build一个非暂时的“firstLetter”属性,每次设置“name”属性时都会更新它。 几种方法来做到这一点:重写“setName:”评估者,覆盖“willSave”,KVO。
看到我的答案在这里类似的问题,我在这里描述如何创build本地化的sectionKey索引是持久的(因为你不能sorting在NSFetchedResultsController中的瞬态属性)。