NSFetchedResultsController部分使用显示顺序排序

时间:2010-12-08 06:31:30

标签: ios core-data nsfetchedresultscontroller

我目前有一个选项,允许用户更改我的iPhone应用程序中类别的显示顺序。

我想使用NSFetchedResultsController对表视图进行分区,以便节标题是“category.displayOrder”排序的“category.name”,其中“category”与我正在获取的实体具有TO-ONE关系。我可以让切片正常工作的唯一方法是使用“category.displayOrder”作为节标题。

NSSortDescriptor *sortDescriptor1 = [[NSSortDescriptor alloc] initWithKey:@"category.displayOrder" ascending:YES];
NSSortDescriptor *sortDescriptor2 = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];

NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor1, sortDescriptor2, nil];

[fetchRequest setSortDescriptors:sortDescriptors];

[fetchRequest setFetchBatchSize:10];

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

关于我如何将部分标题命名为与我正在排序的属性不同的任何想法?

4 个答案:

答案 0 :(得分:15)

不确定我是否完全理解你的问题,但我在我的应用程序中做了类似的事情,这是我如何让它工作:

首先是fetchedResultsController方法,我根据我的目的设置排序描述和谓词。在这种情况下,我想按照发布日期THEN按名称对电影标题进行排序。然后使用我的谓词,我会抓取特定“类型”的实体并在某个​​“releaseDate”范围内。

在我的fetchresultscontroller定义中,您将sectionNameKeyPath设置为“releaseDate”,因此我的节标题将基于日期。

- (NSFetchedResultsController *)fetchedResultsController {

    if (fetchedResultsController_ != nil) {
        return fetchedResultsController_;
    }
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSSortDescriptor *sortByReleaseDate = [[NSSortDescriptor alloc] initWithKey:@"releaseDate" ascending:NO];
    NSSortDescriptor *sortByName = [[NSSortDescriptor alloc] initWithKey:@"title" ascending:YES];
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortByReleaseDate,sortByName, nil];
    [fetchRequest setSortDescriptors:sortDescriptors];
    [sortDescriptors release];
    [sortByName release];
    [sortByReleaseDate release];            
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(type == 'Movies') AND (releaseDate <= %@) AND (releaseDate >= %@)", [NSDate date], [NSDate dateWithTimeIntervalSinceNow:kOneDayTimeInterval*-30]];
    [fetchRequest setPredicate:predicate];

    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Movie" inManagedObjectContext:self.managedObjectContext];
        [fetchRequest setEntity:entity];

    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"releaseDate" cacheName:nil];

    ...// Perform and return fetch here, error handling etc...

    return fetchedResultsController_;

}    

然后在我的表视图数据源委托方法中,我将NSDate转换为NSString后返回每个标题的实际标题(记住你必须为表视图标题标题返回NSString。

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {

    NSString *rawDateStr = [[[self.fetchedResultsController sections] objectAtIndex:section] name];
    //convert default date string to NSDate...
    NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease];
    [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss ZZ"];
    NSDate *date = [formatter dateFromString:rawDateStr];

    //convert NSDate to format we want...
    [formatter setDateFormat:@"d MMMM yyyy"];
    NSString *formattedDateStr = [formatter stringFromDate:date];
    return formattedDateStr;

}

因此,如果我想更改我的数据显示方式,例如titleName,我将把fetchedResultsController对象更改为:

NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"titleName" cacheName:nil];

修改我的tableview:titleForHeaderInSection:数据源方法只返回titleName(已经是一个字符串):

 - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {

        return [[[self.fetchedResultsController sections] objectAtIndex:section] name];
}

我希望这有助于您找到解决特定问题的方法。

干杯, ROG

答案 1 :(得分:10)

我有同样的问题,我有另一个解决方案 - 对sectionNameKeyPath使用transient属性,即category.sectionName。似乎如果你使用核心数据属性作为sectionNameKeyPath,它将尝试使用它进行排序。

所以使用上面的例子:

NSSortDescriptor *sortDescriptor1 = [[NSSortDescriptor alloc] initWithKey:@"category.displayOrder" ascending:YES];
NSSortDescriptor *sortDescriptor2 = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor1, sortDescriptor2, nil];
[fetchRequest setSortDescriptors:sortDescriptors];

NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:@"category.sectionName" cacheName:nil];

Category.h:

@interface Category : NSManagedObject

@property (nonatomic, retain) NSString* name;
@property (nonatomic, retain) NSNumber* displayOrder;

-(NSString*) sectionName;

@end

Category.m:

@implementation Category

@dynamic name;
@dynamic displayOrder;

-(NSString*) sectionName{
    return self.name;
}

@end

然后在你的视图控制器中:

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

答案 2 :(得分:3)

感谢Rog,我能够解决这个问题并提出解决方案。它并不像我想要的那样干净,所以如果有人有更好的方法,我很乐意听到它。

根据我所学的内容(我可能错了,请告诉我),您只能通过订购表格的属性来命名部分(sectionNameKeyPath)。在我的情况下,我想使用名为displayOrder的属性对表进行排序,但我不希望我的节标题为0,1,2等。相反,我希望节标题使用title属性&# 34; Name1&#34;,&#34; Name2&#34;等对应于displayOrder。为此,我根据titleForHeaderInSection中的displayOrder确定标题标题:

        NSString *displayOrder = [sectionInfo name];

        NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
        [fetchRequest setEntity:[NSEntityDescription entityForName:@"Platform" inManagedObjectContext:managedObjectContext]];

        NSNumberFormatter * numberFormatter = [[NSNumberFormatter alloc] init];
        [numberFormatter setNumberStyle:NSNumberFormatterNoStyle];

        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"displayOrder == %@", [numberFormatter numberFromString:displayOrder]];
        [fetchRequest setPredicate:predicate];

        Platform *platform;
        NSError *error = nil;
        NSArray *fetchResults = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
        if ([fetchResults count] > 0) {
            platform = [fetchResults objectAtIndex:0];
            headerView.titleLabel.text = [platform name];
        } else {
            headerView.titleLabel.text = @"Unknown";
        }

        [numberFormatter release];
        [fetchRequest release];

谢谢Rog!

答案 3 :(得分:0)

就我而言,我必须使用RTFM:

- initWithFetchRequest:managedObjectContext:sectionNameKeyPath:cacheName:

  

如果此 sectionNameKeyPath 与fetchRequest中第一个排序描述符指定的不一致,则必须生成相同相对排序。例如,fetchRequest中的第一个排序描述符可能指定持久属性的键; sectionNameKeyPath可以指定从持久属性派生的瞬态属性的键。

当托管对象的sectionNameKeyPathNSSortDescriptor属性更改为与其他属性不同的排序顺序时,在表视图排序中创建了不一致。

来源:
https://richardwarrender.com/2010/10/core-data-objects-in-wrong-sections/