NSFetchedResultsController 使用显示顺序进行节排序

发布于 2024-10-07 01:20:14 字数 1225 浏览 1 评论 0原文

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

我想使用 NSFetchedResultsController 对表视图进行分段,以便部分标题是按“category.displayOrder”排序的“category.name”,其中“category”与我正在获取的实体具有一对一关系。我可以使分段正常工作的唯一方法是使用“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];

关于如何将部分标题命名为与我要排序的属性不同的名称,有什么想法吗?

I currently have an option that allows a user to change the display order of a category in my iPhone app.

I want to section the table view using a NSFetchedResultsController so that the section titles are the "category.name" ordered by "category.displayOrder" where "category" has a TO-ONE relationship with the entity I am fetching. The only way I can get the sectioning to work correctly is by using "category.displayOrder" as the section title.

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];

Any ideas on how I can name the section title something different then the property I am sorting with?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

月亮是我掰弯的 2024-10-14 01:20:14

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

首先,fetchedResultsController 方法,我在其中根据我想要做的事情设置排序描述和谓词。在本例中,我想按发行日期然后按名称对电影标题进行排序。然后,通过我的谓词,我获取特定“类型”和特定“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];
}

我希望这可以帮助您找到解决方案具体问题

干杯,
罗格

Not sure if I understand your question completely, but I do something similar in my app and here's how I get it to work:

Firstly, the fetchedResultsController method, where I set the sort descriptions and predicates based on what I am trying to do. In this case I want to sort movie titles by release date THEN by name. Then with my predicate I grab entities of a specific 'type' and within a certain 'releaseDate' range.

In my fetchresultscontroller definition, you set the sectionNameKeyPath to "releaseDate" so my section headers will be based on a date.

- (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_;

}    

Then in my table view data source delegate methods, I return the actual title for each header after transforming my NSDate into NSString (remember you have to return NSString for a tableview header title.

- (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;

}

So if I wanted to change the way my data is being displayed to be organised by titleName for instance, I'd change my fetchedResultsController object to:

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

And modify my tableview:titleForHeaderInSection: data source method to simply return the titleName (which is already a string):

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

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

I hope this helps you find a solution to your specific problem.

Cheers,
Rog

和影子一齐双人舞 2024-10-14 01:20:14

我遇到了同样的问题,并且有另一个解决方案 - 对sectionNameKeyPath 使用瞬态属性,即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;
}

I had the same problem and I've another solution - use a transient property for the sectionNameKeyPath i.e. category.sectionName. It seems that if you use a core data property as a sectionNameKeyPath it will try and sort with that.

So using your example above:

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

Then in your view controller:

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
    id<NSFetchedResultsSectionInfo> sectionInfo=[self.resultsController.sections objectAtIndex:section];
    return sectionInfo.name;
}
旧城空念 2024-10-14 01:20:14

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

根据我所了解到的(我可能是错的,请告诉我),您只能根据您在其中订购表的属性来命名部分(sectionNameKeyPath)。就我而言,我想使用名为 displayOrder 的属性对表进行排序,但我不希望我的节标题为 0、1、2 等。相反,我希望节标题使用标题属性“Name1”,与displayOrder对应的“Name2”等。为此,我根据 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!

Thanks to Rog I was able to wrap my head around this problem and come up with a solution. It's not as clean as I would want it so if anyone has a better approach I would love to hear about it.

Based on what I have learned (I could be wrong, please let me know) you can only name sections (sectionNameKeyPath) by the property in which you are ordering your table. In my case, I wanted to sort my table using a property called displayOrder, but I didn't want my sections titles to be 0, 1, 2, etc. Instead I wanted the section titles to use the title property "Name1", "Name2", etc. that corresponds to the displayOrder. To do this I determine the header title based on the displayOrder in titleForHeaderInSection:

        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];

Thanks Rog!

晚雾 2024-10-14 01:20:14

就我而言,我必须 RTFM:

- initWithFetchRequest:managementObjectContext:sectionNameKeyPath:cacheName:

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

当托管对象的 sectionNameKeyPathNSSortDescriptor 属性更改为与其他属性不同的排序顺序时,这会导致表视图排序不一致。

来源:
https://richardwarrender.com/2010/10/core-错误部分中的数据对象/

In my case I had to RTFM:

- initWithFetchRequest:managedObjectContext:sectionNameKeyPath:cacheName:

If this sectionNameKeyPath is not the same as that specified by the first sort descriptor in fetchRequest, they must generate the same relative orderings. For example, the first sort descriptor in fetchRequest might specify the key for a persistent property; sectionNameKeyPath might specify a key for a transient property derived from the persistent property.

Which was creating inconsistencies in the Table View ordering when either the sectionNameKeyPath or NSSortDescriptor property of the managed object changed to a different sort order than the other property.

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文